home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / ex_cmds2.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-25  |  110.4 KB  |  4,725 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9.  
  10. /*
  11.  * ex_cmds2.c: some more functions for command line commands
  12.  */
  13.  
  14. #include "vim.h"
  15. #include "version.h"
  16.  
  17. static void    cmd_source __ARGS((char_u *fname, int forceit));
  18.  
  19. #if defined(FEAT_EVAL) || defined(PROTO)
  20.  
  21. /*
  22.  * do_debug(): Debug mode.
  23.  * Repeatedly get Ex commands, until told to continue normal execution.
  24.  */
  25.     void
  26. do_debug(cmd)
  27.     char_u    *cmd;
  28. {
  29.     int        save_msg_scroll = msg_scroll;
  30.     int        save_State = State;
  31.     int        save_did_emsg = did_emsg;
  32.     int        save_cmd_silent = cmd_silent;
  33.     int        n;
  34.     char_u    *cmdline = NULL;
  35.     char_u    *p;
  36.     char    *tail = NULL;
  37.     static int    last_cmd = 0;
  38. #define CMD_CONT    1
  39. #define CMD_NEXT    2
  40. #define CMD_STEP    3
  41. #define CMD_FINISH    4
  42. #define CMD_QUIT    5
  43.  
  44. #ifdef ALWAYS_USE_GUI
  45.     /* Can't do this when there is no terminal for input/output. */
  46.     if (!gui.in_use)
  47.     {
  48.     /* Break as soon as possible. */
  49.     debug_break_level = 9999;
  50.     return;
  51.     }
  52. #endif
  53.  
  54.     /* Make sure we are in raw mode and start termcap mode.  Might have side
  55.      * effects... */
  56.     settmode(TMODE_RAW);
  57.     starttermcap();
  58.  
  59.     ++RedrawingDisabled;        /* don't redisplay the window */
  60.     ++no_wait_return;            /* don't wait for return */
  61.     did_emsg = FALSE;            /* don't use error from debugged stuff */
  62.     cmd_silent = FALSE;            /* display commands */
  63.  
  64.     State = NORMAL;
  65. #ifdef FEAT_SNIFF
  66.     want_sniff_request = 0;    /* No K_SNIFF wanted */
  67. #endif
  68.  
  69.     if (!debug_did_msg)
  70.     MSG(_("Entering Debug mode.  Type \"cont\" to leave."));
  71.     if (sourcing_name != NULL)
  72.     msg(sourcing_name);
  73.     if (sourcing_lnum != 0)
  74.     smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
  75.     else
  76.     smsg((char_u *)_("cmd: %s"), cmd);
  77.  
  78.     /*
  79.      * Repeat getting a command and executing it.
  80.      */
  81.     for (;;)
  82.     {
  83.     msg_scroll = TRUE;
  84.     need_wait_return = FALSE;
  85. #ifdef FEAT_SNIFF
  86.     ProcessSniffRequests();
  87. #endif
  88.     cmdline = getcmdline_prompt('>', NULL, 0);
  89.     cmdline_row = msg_row;
  90.     if (cmdline != NULL)
  91.     {
  92.         /* If this is a debug command, set "last_cmd".
  93.          * If not, reset "last_cmd".
  94.          * For a blank line use previous command. */
  95.         p = skipwhite(cmdline);
  96.         if (*p != NUL)
  97.         {
  98.         switch (*p)
  99.         {
  100.             case 'c': last_cmd = CMD_CONT;
  101.                   tail = "ont";
  102.                   break;
  103.             case 'n': last_cmd = CMD_NEXT;
  104.                   tail = "ext";
  105.                   break;
  106.             case 's': last_cmd = CMD_STEP;
  107.                   tail = "tep";
  108.                   break;
  109.             case 'f': last_cmd = CMD_FINISH;
  110.                   tail = "inish";
  111.                   break;
  112.             case 'q': last_cmd = CMD_QUIT;
  113.                   tail = "uit";
  114.                   break;
  115.             default: last_cmd = 0;
  116.         }
  117.         if (last_cmd != 0)
  118.         {
  119.             /* Check that the tail matches. */
  120.             ++p;
  121.             while (*p != NUL && *p == *tail)
  122.             {
  123.             ++p;
  124.             ++tail;
  125.             }
  126.             if (ASCII_ISALPHA(*p))
  127.             last_cmd = 0;
  128.         }
  129.         }
  130.  
  131.         if (last_cmd != 0)
  132.         {
  133.         /* Execute debug command: decided where to break next and
  134.          * return. */
  135.         switch (last_cmd)
  136.         {
  137.             case CMD_CONT:
  138.             debug_break_level = -1;
  139.             break;
  140.             case CMD_NEXT:
  141.             debug_break_level = debug_level;
  142.             break;
  143.             case CMD_STEP:
  144.             debug_break_level = 9999;
  145.             break;
  146.             case CMD_FINISH:
  147.             debug_break_level = debug_level - 1;
  148.             break;
  149.             case CMD_QUIT:
  150.             got_int = TRUE;
  151.             debug_break_level = -1;
  152.             break;
  153.         }
  154.         break;
  155.         }
  156.  
  157.         /* don't debug this command */
  158.         n = debug_break_level;
  159.         debug_break_level = -1;
  160.         (void)do_cmdline(cmdline, getexline, NULL, DOCMD_VERBOSE);
  161.         debug_break_level = n;
  162.  
  163.         vim_free(cmdline);
  164.     }
  165.     lines_left = Rows - 1;
  166.     }
  167.     vim_free(cmdline);
  168.  
  169.     --RedrawingDisabled;
  170.     --no_wait_return;
  171.     redraw_all_later(NOT_VALID);
  172.     need_wait_return = FALSE;
  173.     msg_scroll = save_msg_scroll;
  174.     lines_left = Rows - 1;
  175.     State = save_State;
  176.     did_emsg = save_did_emsg;
  177.     cmd_silent = save_cmd_silent;
  178.  
  179.     /* Only print the message again when typing a command before coming back
  180.      * here. */
  181.     debug_did_msg = TRUE;
  182. }
  183.  
  184. /*
  185.  * ":debug".
  186.  */
  187.     void
  188. ex_debug(eap)
  189.     exarg_T    *eap;
  190. {
  191.     int        debug_break_level_save = debug_break_level;
  192.  
  193.     debug_break_level = 9999;
  194.     do_cmdline_cmd(eap->arg);
  195.     debug_break_level = debug_break_level_save;
  196. }
  197.  
  198. static char_u    *debug_breakpoint_name = NULL;
  199. static linenr_T    debug_breakpoint_lnum;
  200.  
  201. /*
  202.  * Go to debug mode when a breakpoint was encountered or "debug_level" is
  203.  * at or below the break level.  But only when the line is actually
  204.  * executed.
  205.  * Called from do_one_cmd() before executing a command.
  206.  */
  207.     void
  208. dbg_check_breakpoint(eap)
  209.     exarg_T    *eap;
  210. {
  211.     char_u    *p;
  212.  
  213.     if (debug_breakpoint_name != NULL)
  214.     {
  215.     if (!eap->skip)
  216.     {
  217.         /* replace K_SNR with "<SNR>" */
  218.         if (debug_breakpoint_name[0] == K_SPECIAL
  219.             && debug_breakpoint_name[1] == KS_EXTRA
  220.             && debug_breakpoint_name[2] == (int)KE_SNR)
  221.         p = (char_u *)"<SNR>";
  222.         else
  223.         p = (char_u *)"";
  224.         smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"), p,
  225.             debug_breakpoint_name + (*p == NUL ? 0 : 3),
  226.             (long)debug_breakpoint_lnum);
  227.         debug_breakpoint_name = NULL;
  228.         do_debug(eap->cmd);
  229.     }
  230.     else
  231.         debug_breakpoint_name = NULL;
  232.     }
  233.     else if (!eap->skip && debug_level <= debug_break_level)
  234.     do_debug(eap->cmd);
  235. }
  236.  
  237. /*
  238.  * The list of breakpoints: dbg_breakp.
  239.  * This is a grow-array of structs.
  240.  */
  241. struct debuggy
  242. {
  243.     int        dbg_nr;        /* breakpoint number */
  244.     int        dbg_type;    /* DBG_FUNC or DBG_FILE */
  245.     char_u    *dbg_name;    /* function or file name */
  246.     regprog_T    *dbg_prog;    /* regexp program */
  247.     linenr_T    dbg_lnum;    /* line number in function or file */
  248. };
  249.  
  250. static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
  251. #define BREAKP(idx)    (((struct debuggy *)dbg_breakp.ga_data)[idx])
  252. static int last_breakp = 0;    /* nr of last defined breakpoint */
  253.  
  254. #define DBG_FUNC    1
  255. #define DBG_FILE    2
  256.  
  257. static int dbg_parsearg __ARGS((char_u *arg));
  258.  
  259. /*
  260.  * Parse the arguments of ":breakadd" or ":breakdel" and put them in the entry
  261.  * just after the last one in dbg_breakp.  Note that "dbg_name" is allocated.
  262.  * Returns FAIL for failure.
  263.  */
  264.     static int
  265. dbg_parsearg(arg)
  266.     char_u    *arg;
  267. {
  268.     char_u    *p = arg;
  269.     struct debuggy *bp;
  270.  
  271.     if (ga_grow(&dbg_breakp, 1) == FAIL)
  272.     return FAIL;
  273.     bp = &BREAKP(dbg_breakp.ga_len);
  274.  
  275.     /* Find "func" or "file". */
  276.     if (STRNCMP(p, "func", 4) == 0)
  277.     bp->dbg_type = DBG_FUNC;
  278.     else if (STRNCMP(p, "file", 4) == 0)
  279.     bp->dbg_type = DBG_FILE;
  280.     else
  281.     {
  282.     EMSG2(_(e_invarg2), p);
  283.     return FAIL;
  284.     }
  285.     p = skipwhite(p + 4);
  286.  
  287.     /* Find optional line number. */
  288.     if (isdigit(*p))
  289.     {
  290.     bp->dbg_lnum = getdigits(&p);
  291.     p = skipwhite(p);
  292.     }
  293.     else
  294.     bp->dbg_lnum = 0;
  295.  
  296.     /* Find the function or file name.  Don't accept a function name with (). */
  297.     if (*p == NUL
  298.         || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
  299.     {
  300.     EMSG2(_(e_invarg2), arg);
  301.     return FAIL;
  302.     }
  303.     if ((bp->dbg_name = vim_strsave(p)) == NULL)
  304.     return FAIL;
  305.     return OK;
  306. }
  307.  
  308. /*
  309.  * ":breakadd".
  310.  */
  311.     void
  312. ex_breakadd(eap)
  313.     exarg_T    *eap;
  314. {
  315.     struct debuggy *bp;
  316.     char_u    *pat;
  317.  
  318.     if (dbg_parsearg(eap->arg) == OK)
  319.     {
  320.     bp = &BREAKP(dbg_breakp.ga_len);
  321.     pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
  322.     if (pat != NULL)
  323.     {
  324.         bp->dbg_prog = vim_regcomp(pat, TRUE);
  325.         vim_free(pat);
  326.     }
  327.     if (pat == NULL || bp->dbg_prog == NULL)
  328.         vim_free(bp->dbg_name);
  329.     else
  330.     {
  331.         if (bp->dbg_lnum == 0)    /* default line number is 1 */
  332.         bp->dbg_lnum = 1;
  333.         BREAKP(dbg_breakp.ga_len++).dbg_nr = ++last_breakp;
  334.         --dbg_breakp.ga_room;
  335.         ++debug_tick;
  336.     }
  337.     }
  338. }
  339.  
  340. /*
  341.  * ":breakdel".
  342.  */
  343.     void
  344. ex_breakdel(eap)
  345.     exarg_T    *eap;
  346. {
  347.     struct debuggy *bp, *bpi;
  348.     int        nr;
  349.     int        todel = -1;
  350.     int        i;
  351.     linenr_T    best_lnum = 0;
  352.  
  353.     if (isdigit(*eap->arg))
  354.     {
  355.     /* ":breakdel {nr}" */
  356.     nr = atol((char *)eap->arg);
  357.     for (i = 0; i < dbg_breakp.ga_len; ++i)
  358.         if (BREAKP(i).dbg_nr == nr)
  359.         {
  360.         todel = i;
  361.         break;
  362.         }
  363.     }
  364.     else
  365.     {
  366.     /* ":breakdel {func|file} [lnum] {name}" */
  367.     if (dbg_parsearg(eap->arg) == FAIL)
  368.         return;
  369.     bp = &BREAKP(dbg_breakp.ga_len);
  370.     for (i = 0; i < dbg_breakp.ga_len; ++i)
  371.     {
  372.         bpi = &BREAKP(i);
  373.         if (bp->dbg_type == bpi->dbg_type
  374.             && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
  375.             && (bp->dbg_lnum == bpi->dbg_lnum
  376.             || (bp->dbg_lnum == 0
  377.                 && (best_lnum == 0
  378.                 || bpi->dbg_lnum < best_lnum))))
  379.         {
  380.         todel = i;
  381.         best_lnum = bpi->dbg_lnum;
  382.         }
  383.     }
  384.     vim_free(bp->dbg_name);
  385.     }
  386.  
  387.     if (todel < 0)
  388.     EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
  389.     else
  390.     {
  391.     vim_free(BREAKP(todel).dbg_name);
  392.     vim_free(BREAKP(todel).dbg_prog);
  393.     --dbg_breakp.ga_len;
  394.     ++dbg_breakp.ga_room;
  395.     if (todel < dbg_breakp.ga_len)
  396.         mch_memmove(&BREAKP(todel), &BREAKP(todel + 1),
  397.             (dbg_breakp.ga_len - todel) * sizeof(struct debuggy));
  398.     ++debug_tick;
  399.     }
  400. }
  401.  
  402. /*
  403.  * ":breaklist".
  404.  */
  405. /*ARGSUSED*/
  406.     void
  407. ex_breaklist(eap)
  408.     exarg_T    *eap;
  409. {
  410.     struct debuggy *bp;
  411.     int        i;
  412.  
  413.     if (dbg_breakp.ga_len == 0)
  414.     MSG(_("No breakpoints defined"));
  415.     else
  416.     for (i = 0; i < dbg_breakp.ga_len; ++i)
  417.     {
  418.         bp = &BREAKP(i);
  419.         smsg((char_u *)_("%3d  %s %s  line %ld"),
  420.             bp->dbg_nr,
  421.             bp->dbg_type == DBG_FUNC ? "func" : "file",
  422.             bp->dbg_name,
  423.             (long)bp->dbg_lnum);
  424.     }
  425. }
  426.  
  427. /*
  428.  * Find a breakpoint for a function or sourced file.
  429.  * Returns line number at which to break; zero when no matching breakpoint.
  430.  */
  431.     linenr_T
  432. dbg_find_breakpoint(file, fname, after)
  433.     int        file;        /* TRUE for a file, FALSE for a function */
  434.     char_u    *fname;        /* file or function name */
  435.     linenr_T    after;        /* after this line number */
  436. {
  437.     struct debuggy *bp;
  438.     int        i;
  439.     linenr_T    lnum = 0;
  440.     regmatch_T    regmatch;
  441.     char_u    *name = fname;
  442.  
  443.     /* Replace K_SNR in function name with "<SNR>". */
  444.     if (!file && fname[0] == K_SPECIAL)
  445.     {
  446.     name = alloc((unsigned)STRLEN(fname) + 3);
  447.     if (name == NULL)
  448.         name = fname;
  449.     else
  450.     {
  451.         STRCPY(name, "<SNR>");
  452.         STRCPY(name + 5, fname + 3);
  453.     }
  454.     }
  455.  
  456.     for (i = 0; i < dbg_breakp.ga_len; ++i)
  457.     {
  458.     /* skip entries that are not useful or are for a line that is beyond
  459.      * an already found breakpoint */
  460.     bp = &BREAKP(i);
  461.     if ((bp->dbg_type == DBG_FILE) == file
  462.         && bp->dbg_lnum > after
  463.         && (lnum == 0 || bp->dbg_lnum < lnum))
  464.     {
  465.         regmatch.regprog = bp->dbg_prog;
  466.         regmatch.rm_ic = FALSE;
  467.         if (vim_regexec(®match, name, (colnr_T)0))
  468.         lnum = bp->dbg_lnum;
  469.     }
  470.     }
  471.     if (name != fname)
  472.     vim_free(name);
  473.  
  474.     return lnum;
  475. }
  476.  
  477. /*
  478.  * Called when a breakpoint was encountered.
  479.  */
  480.     void
  481. dbg_breakpoint(name, lnum)
  482.     char_u    *name;
  483.     linenr_T    lnum;
  484. {
  485.     /* We need to check if this line is actually executed in do_one_cmd() */
  486.     debug_breakpoint_name = name;
  487.     debug_breakpoint_lnum = lnum;
  488. }
  489. #endif
  490.  
  491. /*
  492.  * If 'autowrite' option set, try to write the file.
  493.  * Careful: autocommands may make "buf" invalid!
  494.  *
  495.  * return FAIL for failure, OK otherwise
  496.  */
  497.     int
  498. autowrite(buf, forceit)
  499.     buf_T    *buf;
  500.     int        forceit;
  501. {
  502.     if (!(p_aw || p_awa) || !p_write
  503. #ifdef FEAT_QUICKFIX
  504.     /* never autowrite a "nofile" or "nowrite" buffer */
  505.     || bt_dontwrite(buf)
  506. #endif
  507.     || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
  508.     return FAIL;
  509.     return buf_write_all(buf, forceit);
  510. }
  511.  
  512. /*
  513.  * flush all buffers, except the ones that are readonly
  514.  */
  515.     void
  516. autowrite_all()
  517. {
  518.     buf_T    *buf;
  519.  
  520.     if (!(p_aw || p_awa) || !p_write)
  521.     return;
  522.     for (buf = firstbuf; buf; buf = buf->b_next)
  523.     if (bufIsChanged(buf) && !buf->b_p_ro)
  524.     {
  525.         (void)buf_write_all(buf, FALSE);
  526. #ifdef FEAT_AUTOCMD
  527.         /* an autocommand may have deleted the buffer */
  528.         if (!buf_valid(buf))
  529.         buf = firstbuf;
  530. #endif
  531.     }
  532. }
  533.  
  534. /*
  535.  * return TRUE if buffer was changed and cannot be abandoned.
  536.  */
  537. /*ARGSUSED*/
  538.     int
  539. check_changed(buf, checkaw, mult_win, forceit, allbuf)
  540.     buf_T    *buf;
  541.     int        checkaw;    /* do autowrite if buffer was changed */
  542.     int        mult_win;    /* check also when several wins for the buf */
  543.     int        forceit;
  544.     int        allbuf;        /* may write all buffers */
  545. {
  546.     if (       !forceit
  547.         && bufIsChanged(buf)
  548.         && (mult_win || buf->b_nwindows <= 1)
  549.         && (!checkaw || autowrite(buf, forceit) == FAIL))
  550.     {
  551. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  552.     if ((p_confirm || cmdmod.confirm) && p_write)
  553.     {
  554.         buf_T    *buf2;
  555.         int        count = 0;
  556.  
  557.         if (allbuf)
  558.         for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
  559.             if (bufIsChanged(buf2)
  560.                      && (buf2->b_ffname != NULL
  561. # ifdef FEAT_BROWSE
  562.                      || cmdmod.browse
  563. # endif
  564.                     ))
  565.             ++count;
  566. #ifdef FEAT_AUTOCMD
  567.         if (!buf_valid(buf))
  568.         /* Autocommand deleted buffer, oops!  It's not changed now. */
  569.         return FALSE;
  570. #endif
  571.         dialog_changed(buf, count > 1);
  572. #ifdef FEAT_AUTOCMD
  573.         if (!buf_valid(buf))
  574.         /* Autocommand deleted buffer, oops!  It's not changed now. */
  575.         return FALSE;
  576. #endif
  577.         return bufIsChanged(buf);
  578.     }
  579. #endif
  580.     EMSG(_(e_nowrtmsg));
  581.     return TRUE;
  582.     }
  583.     return FALSE;
  584. }
  585.  
  586. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
  587.  
  588. #ifdef FEAT_BROWSE
  589. static void    browse_save_fname __ARGS((buf_T *buf));
  590.  
  591. /*
  592.  * When wanting to write a file without a file name, ask the user for a name.
  593.  */
  594.     static void
  595. browse_save_fname(buf)
  596.     buf_T    *buf;
  597. {
  598.     if (buf->b_fname == NULL)
  599.     {
  600.     char_u *fname;
  601.  
  602.     fname = do_browse(TRUE, (char_u *)_("Save As"), NULL, NULL, NULL,
  603.                                    NULL, buf);
  604.     if (fname != NULL)
  605.     {
  606.         setfname(fname, NULL, TRUE);
  607.         vim_free(fname);
  608.     }
  609.     }
  610. }
  611. #endif
  612.  
  613. /*
  614.  * Ask the user what to do when abondoning a changed buffer.
  615.  */
  616.     void
  617. dialog_changed(buf, checkall)
  618.     buf_T    *buf;
  619.     int        checkall;    /* may abandon all changed buffers */
  620. {
  621.     char_u    buff[IOSIZE];
  622.     int        ret;
  623.     buf_T    *buf2;
  624.  
  625.     dialog_msg(buff, _("Save changes to \"%.*s\"?"),
  626.             (buf->b_fname != NULL) ?
  627.             buf->b_fname : (char_u *)_("Untitled"));
  628.     if (checkall)
  629.     ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
  630.     else
  631.     ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
  632.  
  633.     if (ret == VIM_YES)
  634.     {
  635. #ifdef FEAT_BROWSE
  636.     /* May get file name, when there is none */
  637.     browse_save_fname(buf);
  638. #endif
  639.     if (buf->b_fname != NULL)   /* didn't hit Cancel */
  640.         (void)buf_write_all(buf, FALSE);
  641.     }
  642.     else if (ret == VIM_NO)
  643.     {
  644.     unchanged(buf, TRUE);
  645.     }
  646.     else if (ret == VIM_ALL)
  647.     {
  648.     /*
  649.      * Write all modified files that can be written.
  650.      * Skip readonly buffers, these need to be confirmed
  651.      * individually.
  652.      */
  653.     for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
  654.     {
  655.         if (bufIsChanged(buf2)
  656.             && (buf2->b_ffname != NULL
  657. #ifdef FEAT_BROWSE
  658.             || cmdmod.browse
  659. #endif
  660.             )
  661.             && !buf2->b_p_ro)
  662.         {
  663. #ifdef FEAT_BROWSE
  664.         /* May get file name, when there is none */
  665.         browse_save_fname(buf2);
  666. #endif
  667.         if (buf2->b_fname != NULL)   /* didn't hit Cancel */
  668.             (void)buf_write_all(buf2, FALSE);
  669. #ifdef FEAT_AUTOCMD
  670.         /* an autocommand may have deleted the buffer */
  671.         if (!buf_valid(buf2))
  672.             buf2 = firstbuf;
  673. #endif
  674.         }
  675.     }
  676.     }
  677.     else if (ret == VIM_DISCARDALL)
  678.     {
  679.     /*
  680.      * mark all buffers as unchanged
  681.      */
  682.     for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
  683.         unchanged(buf2, TRUE);
  684.     }
  685. }
  686. #endif
  687.  
  688. /*
  689.  * Return TRUE if the buffer "buf" can be abandoned, either by making it
  690.  * hidden, autowriting it or unloading it.
  691.  */
  692.     int
  693. can_abandon(buf, forceit)
  694.     buf_T    *buf;
  695.     int        forceit;
  696. {
  697.     return (       P_HID(buf)
  698.         || !bufIsChanged(buf)
  699.         || buf->b_nwindows > 1
  700.         || autowrite(buf, forceit) == OK
  701.         || forceit);
  702. }
  703.  
  704. /*
  705.  * Return TRUE if any buffer was changed and cannot be abandoned.
  706.  * That changed buffer becomes the current buffer.
  707.  */
  708.     int
  709. check_changed_any(hidden)
  710.     int        hidden;        /* Only check hidden buffers */
  711. {
  712.     buf_T    *buf;
  713.     int        save;
  714. #ifdef FEAT_WINDOWS
  715.     win_T    *wp;
  716. #endif
  717.  
  718. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  719.     for (;;)
  720.     {
  721. #endif
  722.     /* check curbuf first: if it was changed we can't abandon it */
  723.     if (!hidden && curbufIsChanged())
  724.         buf = curbuf;
  725.     else
  726.     {
  727.         for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  728.         if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
  729.             break;
  730.     }
  731.     if (buf == NULL)    /* No buffers changed */
  732.         return FALSE;
  733.  
  734. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  735.     if (p_confirm || cmdmod.confirm)
  736.     {
  737.         if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
  738.         break;        /* didn't save - still changes */
  739.     }
  740.     else
  741.         break;        /* confirm not active - has changes */
  742.     }
  743. #endif
  744.  
  745.     exiting = FALSE;
  746. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  747.     /*
  748.      * When ":confirm" used, don't give an error message.
  749.      */
  750.     if (!(p_confirm || cmdmod.confirm))
  751. #endif
  752.     {
  753.     /* There must be a wait_return for this message, do_buffer()
  754.      * may cause a redraw.  But wait_return() is a no-op when vgetc()
  755.      * is busy (Quit used from window menu), then make sure we don't
  756.      * cause a scroll up. */
  757.     if (vgetc_busy)
  758.     {
  759.         msg_row = cmdline_row;
  760.         msg_col = 0;
  761.         msg_didout = FALSE;
  762.     }
  763.     if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
  764.             buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
  765.             buf->b_fname))
  766.     {
  767.         save = no_wait_return;
  768.         no_wait_return = FALSE;
  769.         wait_return(FALSE);
  770.         no_wait_return = save;
  771.     }
  772.     }
  773.  
  774. #ifdef FEAT_WINDOWS
  775.     /* Try to find a window that contains the buffer. */
  776.     if (buf != curbuf)
  777.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  778.         if (wp->w_buffer == buf)
  779.         {
  780.         win_goto(wp);
  781. # ifdef FEAT_AUTOCMD
  782.         /* Paranoia: did autocms wipe out the buffer with changes? */
  783.         if (!buf_valid(buf))
  784.             return TRUE;
  785. # endif
  786.         break;
  787.         }
  788. #endif
  789.  
  790.     /* Open the changed buffer in the current window. */
  791.     if (buf != curbuf)
  792.     set_curbuf(buf, DOBUF_GOTO);
  793.  
  794.     return TRUE;
  795. }
  796.  
  797. /*
  798.  * return FAIL if there is no file name, OK if there is one
  799.  * give error message for FAIL
  800.  */
  801.     int
  802. check_fname()
  803. {
  804.     if (curbuf->b_ffname == NULL)
  805.     {
  806.     EMSG(_(e_noname));
  807.     return FAIL;
  808.     }
  809.     return OK;
  810. }
  811.  
  812. /*
  813.  * flush the contents of a buffer, unless it has no file name
  814.  *
  815.  * return FAIL for failure, OK otherwise
  816.  */
  817.     int
  818. buf_write_all(buf, forceit)
  819.     buf_T    *buf;
  820.     int        forceit;
  821. {
  822.     int        retval;
  823. #ifdef FEAT_AUTOCMD
  824.     buf_T    *old_curbuf = curbuf;
  825. #endif
  826.  
  827.     retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
  828.                    (linenr_T)1, buf->b_ml.ml_line_count, NULL,
  829.                           FALSE, forceit, TRUE, FALSE));
  830. #ifdef FEAT_AUTOCMD
  831.     if (curbuf != old_curbuf)
  832.     MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
  833. #endif
  834.     return retval;
  835. }
  836.  
  837. /*
  838.  * Code to handle the argument list.
  839.  */
  840. static int do_arglist __ARGS((char_u *str, int what, int after));
  841. static void alist_check_arg_idx __ARGS((void));
  842. #ifdef FEAT_LISTCMDS
  843. static int alist_add_list __ARGS((int count, char_u **files, int after));
  844. #endif
  845. #define AL_SET    1
  846. #define AL_ADD    2
  847. #define AL_DEL    3
  848.  
  849. /*
  850.  * "what" == AL_SET: Redefine the argument list to 'str'.
  851.  * "what" == AL_ADD: add files in 'str' to the argument list after "after".
  852.  * "what" == AL_DEL: remove files in 'str' from the argument list.
  853.  *
  854.  * Return FAIL for failure, OK otherwise.
  855.  */
  856. /*ARGSUSED*/
  857.     static int
  858. do_arglist(str, what, after)
  859.     char_u    *str;
  860.     int        what;
  861.     int        after;        /* 0 means before first one */
  862. {
  863.     garray_T    new_ga;
  864.     int        exp_count;
  865.     char_u    **exp_files;
  866.     char_u    *p;
  867.     int        inquote;
  868.     int        inbacktick;
  869.     int        i;
  870. #ifdef FEAT_LISTCMDS
  871.     int        match;
  872. #endif
  873.  
  874.     /*
  875.      * Collect all file name arguments in "new_ga".
  876.      */
  877.     ga_init2(&new_ga, (int)sizeof(char_u *), 20);
  878.     while (*str)
  879.     {
  880.     if (ga_grow(&new_ga, 1) == FAIL)
  881.     {
  882.         ga_clear(&new_ga);
  883.         return FAIL;
  884.     }
  885.     ((char_u **)new_ga.ga_data)[new_ga.ga_len++] = str;
  886.     --new_ga.ga_room;
  887.  
  888.     /*
  889.      * Isolate one argument, taking quotes and backticks.
  890.      * Quotes are removed, backticks remain.
  891.      */
  892.     inquote = FALSE;
  893.     inbacktick = FALSE;
  894.     for (p = str; *str; ++str)
  895.     {
  896.         /*
  897.          * for MSDOS et.al. a backslash is part of a file name.
  898.          * Only skip ", space and tab.
  899.          */
  900.         if (rem_backslash(str))
  901.         {
  902.         *p++ = *str++;
  903.         *p++ = *str;
  904.         }
  905.         else
  906.         {
  907.         /* An item ends at a space not in quotes or backticks */
  908.         if (!inquote && !inbacktick && vim_isspace(*str))
  909.             break;
  910.         if (!inquote && *str == '`')
  911.             inbacktick ^= TRUE;
  912.         if (!inbacktick && *str == '"')
  913.             inquote ^= TRUE;
  914.         else
  915.             *p++ = *str;
  916.         }
  917.     }
  918.     str = skipwhite(str);
  919.     *p = NUL;
  920.     }
  921.  
  922. #ifdef FEAT_LISTCMDS
  923.     if (what == AL_DEL)
  924.     {
  925.     regmatch_T    regmatch;
  926.     int        didone;
  927.  
  928.     /*
  929.      * Delete the items: use each item as a regexp and find a match in the
  930.      * argument list.
  931.      */
  932. #ifdef CASE_INSENSITIVE_FILENAME
  933.     regmatch.rm_ic = TRUE;        /* Always ignore case */
  934. #else
  935.     regmatch.rm_ic = FALSE;        /* Never ignore case */
  936. #endif
  937.     for (i = 0; i < new_ga.ga_len && !got_int; ++i)
  938.     {
  939.         p = ((char_u **)new_ga.ga_data)[i];
  940.         p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
  941.         if (p == NULL)
  942.         break;
  943.         regmatch.regprog = vim_regcomp(p, (int)p_magic);
  944.         if (regmatch.regprog == NULL)
  945.         {
  946.         vim_free(p);
  947.         break;
  948.         }
  949.  
  950.         didone = FALSE;
  951.         for (match = 0; match < ARGCOUNT; ++match)
  952.         if (vim_regexec(®match, alist_name(&ARGLIST[match]),
  953.                                   (colnr_T)0))
  954.         {
  955.             didone = TRUE;
  956.             vim_free(ARGLIST[match].ae_fname);
  957.             mch_memmove(ARGLIST + match, ARGLIST + match + 1,
  958.                 (ARGCOUNT - match - 1) * sizeof(aentry_T));
  959.             --ALIST(curwin)->al_ga.ga_len;
  960.             ++ALIST(curwin)->al_ga.ga_room;
  961.             if (curwin->w_arg_idx > match)
  962.             --curwin->w_arg_idx;
  963.             --match;
  964.         }
  965.  
  966.         vim_free(regmatch.regprog);
  967.         vim_free(p);
  968.         if (!didone)
  969.         EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
  970.     }
  971.     ga_clear(&new_ga);
  972.     }
  973.     else
  974. #endif
  975.     {
  976.     i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
  977.         &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
  978.     ga_clear(&new_ga);
  979.     if (i == FAIL)
  980.         return FAIL;
  981.     if (exp_count == 0)
  982.     {
  983.         EMSG(_(e_nomatch));
  984.         return FAIL;
  985.     }
  986.  
  987. #ifdef FEAT_LISTCMDS
  988.     if (what == AL_ADD)
  989.     {
  990.         (void)alist_add_list(exp_count, exp_files, after);
  991.         vim_free(exp_files);
  992.     }
  993.     else /* what == AL_SET */
  994. #endif
  995.         alist_set(ALIST(curwin), exp_count, exp_files, FALSE);
  996.     }
  997.  
  998.     alist_check_arg_idx();
  999.  
  1000.     return OK;
  1001. }
  1002.  
  1003. /*
  1004.  * Check the validity of the arg_idx for each other window.
  1005.  */
  1006.     static void
  1007. alist_check_arg_idx()
  1008. {
  1009. #ifdef FEAT_WINDOWS
  1010.     win_T    *win;
  1011.  
  1012.     for (win = firstwin; win != NULL; win = win->w_next)
  1013.     if (win->w_alist == curwin->w_alist)
  1014.         check_arg_idx(win);
  1015. #else
  1016.     check_arg_idx(curwin);
  1017. #endif
  1018. }
  1019.  
  1020. /*
  1021.  * Check if window "win" is editing the w_arg_idx file in its argument list.
  1022.  */
  1023.     void
  1024. check_arg_idx(win)
  1025.     win_T    *win;
  1026. {
  1027.     if (WARGCOUNT(win) > 1
  1028.         && (win->w_arg_idx >= WARGCOUNT(win)
  1029.         || (win->w_buffer->b_fnum
  1030.                       != WARGLIST(win)[win->w_arg_idx].ae_fnum
  1031.             && (win->w_buffer->b_ffname == NULL
  1032.              || !(fullpathcmp(
  1033.                  alist_name(&WARGLIST(win)[win->w_arg_idx]),
  1034.                 win->w_buffer->b_ffname, TRUE) & FPC_SAME)))))
  1035.     {
  1036.     /* We are not editing the current entry in the argument list.
  1037.      * Set "arg_had_last" if we are editing the last one. */
  1038.     win->w_arg_idx_invalid = TRUE;
  1039.     if (win->w_arg_idx != WARGCOUNT(win) - 1
  1040.         && arg_had_last == FALSE
  1041. #ifdef FEAT_WINDOWS
  1042.         && ALIST(win) == &global_alist
  1043. #endif
  1044.         && GARGCOUNT > 0
  1045.         && win->w_arg_idx < GARGCOUNT
  1046.         && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
  1047.             || (win->w_buffer->b_ffname != NULL
  1048.             && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
  1049.                 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
  1050.         arg_had_last = TRUE;
  1051.     }
  1052.     else
  1053.     {
  1054.     /* We are editing the current entry in the argument list.
  1055.      * Set "arg_had_last" if it's also the last one */
  1056.     win->w_arg_idx_invalid = FALSE;
  1057.     if (win->w_arg_idx == WARGCOUNT(win) - 1
  1058. #ifdef FEAT_WINDOWS
  1059.         && win->w_alist == &global_alist
  1060. #endif
  1061.         )
  1062.         arg_had_last = TRUE;
  1063.     }
  1064. }
  1065.  
  1066. /*
  1067.  * ":args", ":argslocal" and ":argsglobal".
  1068.  */
  1069.     void
  1070. ex_args(eap)
  1071.     exarg_T    *eap;
  1072. {
  1073.     int        i;
  1074.  
  1075.     if (eap->cmdidx != CMD_args)
  1076.     {
  1077. #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
  1078.     alist_unlink(ALIST(curwin));
  1079.     if (eap->cmdidx == CMD_argglobal)
  1080.         ALIST(curwin) = &global_alist;
  1081.     else /* eap->cmdidx == CMD_arglocal */
  1082.         alist_new();
  1083. #else
  1084.     ex_ni(eap);
  1085.     return;
  1086. #endif
  1087.     }
  1088.  
  1089.     if (!ends_excmd(*eap->arg))
  1090.     {
  1091.     /*
  1092.      * ":args file ..": define new argument list, handle like ":next"
  1093.      * Also for ":argslocal file .." and ":argsglobal file ..".
  1094.      */
  1095.     ex_next(eap);
  1096.     }
  1097.     else
  1098. #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
  1099.     if (eap->cmdidx == CMD_args)
  1100. #endif
  1101.     {
  1102.     /*
  1103.      * ":args": list arguments.
  1104.      */
  1105.     if (ARGCOUNT > 0)
  1106.     {
  1107.         /* Overwrite the command, for a short list there is no scrolling
  1108.          * required and no wait_return(). */
  1109.         gotocmdline(TRUE);
  1110.         for (i = 0; i < ARGCOUNT; ++i)
  1111.         {
  1112.         if (i == curwin->w_arg_idx)
  1113.             msg_putchar('[');
  1114.         msg_outtrans(alist_name(&ARGLIST[i]));
  1115.         if (i == curwin->w_arg_idx)
  1116.             msg_putchar(']');
  1117.         msg_putchar(' ');
  1118.         }
  1119.     }
  1120.     }
  1121. #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
  1122.     else if (eap->cmdidx == CMD_arglocal)
  1123.     {
  1124.     garray_T    *gap = &curwin->w_alist->al_ga;
  1125.  
  1126.     /*
  1127.      * ":argslocal": make a local copy of the global argument list.
  1128.      */
  1129.     if (ga_grow(gap, GARGCOUNT) == OK)
  1130.         for (i = 0; i < GARGCOUNT; ++i)
  1131.         if (GARGLIST[i].ae_fname != NULL)
  1132.         {
  1133.             AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
  1134.                         vim_strsave(GARGLIST[i].ae_fname);
  1135.             AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
  1136.                               GARGLIST[i].ae_fnum;
  1137.             ++gap->ga_len;
  1138.             --gap->ga_room;
  1139.         }
  1140.     }
  1141. #endif
  1142. }
  1143.  
  1144. /*
  1145.  * ":previous", ":sprevious", ":Next" and ":sNext".
  1146.  */
  1147.     void
  1148. ex_previous(eap)
  1149.     exarg_T    *eap;
  1150. {
  1151.     /* If past the last one already, go to the last one. */
  1152.     if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
  1153.     do_argfile(eap, ARGCOUNT - 1);
  1154.     else
  1155.     do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
  1156. }
  1157.  
  1158. /*
  1159.  * ":rewind", ":first", ":sfirst" and ":srewind".
  1160.  */
  1161.     void
  1162. ex_rewind(eap)
  1163.     exarg_T    *eap;
  1164. {
  1165.     do_argfile(eap, 0);
  1166. }
  1167.  
  1168. /*
  1169.  * ":last" and ":slast".
  1170.  */
  1171.     void
  1172. ex_last(eap)
  1173.     exarg_T    *eap;
  1174. {
  1175.     do_argfile(eap, ARGCOUNT - 1);
  1176. }
  1177.  
  1178. /*
  1179.  * ":argument" and ":sargument".
  1180.  */
  1181.     void
  1182. ex_argument(eap)
  1183.     exarg_T    *eap;
  1184. {
  1185.     int        i;
  1186.  
  1187.     if (eap->addr_count > 0)
  1188.     i = eap->line2 - 1;
  1189.     else
  1190.     i = curwin->w_arg_idx;
  1191.     do_argfile(eap, i);
  1192. }
  1193.  
  1194. /*
  1195.  * Edit file "argn" of the argument lists.
  1196.  */
  1197.     void
  1198. do_argfile(eap, argn)
  1199.     exarg_T    *eap;
  1200.     int        argn;
  1201. {
  1202.     int        other;
  1203.     char_u    *p;
  1204.  
  1205.     if (argn < 0 || argn >= ARGCOUNT)
  1206.     {
  1207.     if (ARGCOUNT <= 1)
  1208.         EMSG(_("E163: There is only one file to edit"));
  1209.     else if (argn < 0)
  1210.         EMSG(_("E164: Cannot go before first file"));
  1211.     else
  1212.         EMSG(_("E165: Cannot go beyond last file"));
  1213.     }
  1214.     else
  1215.     {
  1216.     setpcmark();
  1217. #ifdef FEAT_GUI
  1218.     need_mouse_correct = TRUE;
  1219. #endif
  1220.  
  1221. #ifdef FEAT_WINDOWS
  1222.     if (*eap->cmd == 's')        /* split window first */
  1223.     {
  1224.         if (win_split(0, 0) == FAIL)
  1225.         return;
  1226.     }
  1227.     else
  1228. #endif
  1229.     {
  1230.         /*
  1231.          * if 'hidden' set, only check for changed file when re-editing
  1232.          * the same buffer
  1233.          */
  1234.         other = TRUE;
  1235.         if (P_HID(curbuf))
  1236.         {
  1237.         p = fix_fname(alist_name(&ARGLIST[argn]));
  1238.         other = otherfile(p);
  1239.         vim_free(p);
  1240.         }
  1241.         if ((!P_HID(curbuf) || !other)
  1242.           && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
  1243.         return;
  1244.     }
  1245.  
  1246.     curwin->w_arg_idx = argn;
  1247.     if (argn == ARGCOUNT - 1
  1248. #ifdef FEAT_WINDOWS
  1249.         && curwin->w_alist == &global_alist
  1250. #endif
  1251.        )
  1252.         arg_had_last = TRUE;
  1253.  
  1254.     /* Edit the file; always use the last known line number. */
  1255.     (void)do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
  1256.               eap, ECMD_LAST,
  1257.               (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) +
  1258.                        (eap->forceit ? ECMD_FORCEIT : 0));
  1259.  
  1260.     /* like Vi: set the mark where the cursor is in the file. */
  1261.     setmark('\'');
  1262.     }
  1263. }
  1264.  
  1265. /*
  1266.  * ":next", and commands that behave like it.
  1267.  */
  1268.     void
  1269. ex_next(eap)
  1270.     exarg_T    *eap;
  1271. {
  1272.     int        i;
  1273.  
  1274.     /*
  1275.      * check for changed buffer now, if this fails the argument list is not
  1276.      * redefined.
  1277.      */
  1278.     if (       P_HID(curbuf)
  1279.         || eap->cmdidx == CMD_snext
  1280.         || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
  1281.     {
  1282.     if (*eap->arg != NUL)            /* redefine file list */
  1283.     {
  1284.         if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
  1285.         return;
  1286.         i = 0;
  1287.     }
  1288.     else
  1289.         i = curwin->w_arg_idx + (int)eap->line2;
  1290.     do_argfile(eap, i);
  1291.     }
  1292. }
  1293.  
  1294. #ifdef FEAT_LISTCMDS
  1295. /*
  1296.  * ":argedit"
  1297.  */
  1298.     void
  1299. ex_argedit(eap)
  1300.     exarg_T    *eap;
  1301. {
  1302.     int        fnum;
  1303.     int        i;
  1304.     char_u    *s;
  1305.  
  1306.     /* Add the argument to the buffer list and get the buffer number. */
  1307.     fnum = buflist_add(eap->arg, BLN_LISTED);
  1308.  
  1309.     /* Check if this argument is already in the argument list. */
  1310.     for (i = 0; i < ARGCOUNT; ++i)
  1311.     if (ARGLIST[i].ae_fnum == fnum)
  1312.         break;
  1313.     if (i == ARGCOUNT)
  1314.     {
  1315.     /* Can't find it, add it to the argument list. */
  1316.     s = vim_strsave(eap->arg);
  1317.     if (s == NULL)
  1318.         return;
  1319.     i = alist_add_list(1, &s,
  1320.            eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
  1321.     if (i < 0)
  1322.         return;
  1323.     curwin->w_arg_idx = i;
  1324.     }
  1325.  
  1326.     alist_check_arg_idx();
  1327.  
  1328.     /* Edit the argument. */
  1329.     do_argfile(eap, i);
  1330. }
  1331.  
  1332. /*
  1333.  * ":argadd"
  1334.  */
  1335.     void
  1336. ex_argadd(eap)
  1337.     exarg_T    *eap;
  1338. {
  1339.     do_arglist(eap->arg, AL_ADD,
  1340.            eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
  1341. #ifdef FEAT_TITLE
  1342.     maketitle();
  1343. #endif
  1344. }
  1345.  
  1346. /*
  1347.  * ":argdelete"
  1348.  */
  1349.     void
  1350. ex_argdelete(eap)
  1351.     exarg_T    *eap;
  1352. {
  1353.     int        i;
  1354.     int        n;
  1355.  
  1356.     if (eap->addr_count > 0)
  1357.     {
  1358.     /* ":1,4argdel": Delete all arguments in the range. */
  1359.     if (eap->line2 > ARGCOUNT)
  1360.         eap->line2 = ARGCOUNT;
  1361.     n = eap->line2 - eap->line1 + 1;
  1362.     if (*eap->arg != NUL || n <= 0)
  1363.         EMSG(_(e_invarg));
  1364.     else
  1365.     {
  1366.         for (i = eap->line1; i <= eap->line2; ++i)
  1367.         vim_free(ARGLIST[i - 1].ae_fname);
  1368.         mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
  1369.             (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
  1370.         ALIST(curwin)->al_ga.ga_len -= n;
  1371.         ALIST(curwin)->al_ga.ga_room += n;
  1372.         if (curwin->w_arg_idx >= eap->line2)
  1373.         curwin->w_arg_idx -= n;
  1374.         else if (curwin->w_arg_idx > eap->line1)
  1375.         curwin->w_arg_idx = eap->line1;
  1376.     }
  1377.     }
  1378.     else if (*eap->arg == NUL)
  1379.     EMSG(_(e_argreq));
  1380.     else
  1381.     do_arglist(eap->arg, AL_DEL, 0);
  1382. #ifdef FEAT_TITLE
  1383.     maketitle();
  1384. #endif
  1385. }
  1386.  
  1387. /*
  1388.  * ":argdo", ":windo", ":bufdo"
  1389.  */
  1390.     void
  1391. ex_listdo(eap)
  1392.     exarg_T    *eap;
  1393. {
  1394.     int        i;
  1395. #ifdef FEAT_WINDOWS
  1396.     win_T    *win;
  1397. #endif
  1398.     buf_T    *buf;
  1399. #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
  1400.     char_u    *save_ei = vim_strsave(p_ei);
  1401.     char_u    *new_ei;
  1402. #endif
  1403.  
  1404. #ifndef FEAT_WINDOWS
  1405.     if (eap->cmdidx == CMD_windo)
  1406.     {
  1407.     ex_ni(eap);
  1408.     return;
  1409.     }
  1410. #endif
  1411.  
  1412. #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
  1413.     new_ei = vim_strnsave(p_ei, (int)STRLEN(p_ei) + 8);
  1414.     if (new_ei != NULL)
  1415.     {
  1416.     STRCAT(new_ei, ",Syntax");
  1417.     set_string_option_direct((char_u *)"ei", -1, new_ei, OPT_FREE);
  1418.     vim_free(new_ei);
  1419.     }
  1420. #endif
  1421.  
  1422.     if (eap->cmdidx == CMD_windo
  1423.         || P_HID(curbuf)
  1424.         || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
  1425.     {
  1426.     /* start at the first argument/window/buffer */
  1427.     i = 0;
  1428. #ifdef FEAT_WINDOWS
  1429.     win = firstwin;
  1430. #endif
  1431.     if (eap->cmdidx == CMD_bufdo)
  1432.         goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
  1433.     while (!got_int)
  1434.     {
  1435.         if (eap->cmdidx == CMD_argdo)
  1436.         {
  1437.         /* go to argument "i" */
  1438.         if (i == ARGCOUNT)
  1439.             break;
  1440.         do_argfile(eap, i);
  1441.         if (curwin->w_arg_idx != i)
  1442.             break;
  1443.         ++i;
  1444.         }
  1445. #ifdef FEAT_WINDOWS
  1446.         else if (eap->cmdidx == CMD_windo)
  1447.         {
  1448.         /* go to window "win" */
  1449.         if (!win_valid(win))
  1450.             break;
  1451.         win_goto(win);
  1452.         win = win->w_next;
  1453.         }
  1454. #endif
  1455.  
  1456.         /* execute the command */
  1457.         do_cmdline(eap->arg, eap->getline, eap->cookie,
  1458.                         DOCMD_VERBOSE + DOCMD_NOWAIT);
  1459.  
  1460.         if (eap->cmdidx == CMD_bufdo)
  1461.         {
  1462.         /* Go to the next listed buffer.  Check that we really get
  1463.          * there (no autocommands confused us). */
  1464.         for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
  1465.             if (buf->b_p_bl)
  1466.             break;
  1467.         if (buf == NULL)
  1468.             break;
  1469.         goto_buffer(eap, DOBUF_CURRENT, FORWARD, 1);
  1470.         if (curbuf != buf)
  1471.             break;
  1472.         }
  1473.  
  1474. #ifdef FEAT_SCROLLBIND
  1475.         if (eap->cmdidx == CMD_windo && curwin->w_p_scb)
  1476.         {
  1477.         /* required when 'scrollbind' has been set */
  1478.         validate_cursor();    /* may need to update w_leftcol */
  1479.         do_check_scrollbind(TRUE);
  1480.         }
  1481. #endif
  1482.     }
  1483.     }
  1484. #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
  1485.     if (new_ei != NULL)
  1486.     {
  1487.     set_string_option_direct((char_u *)"ei", -1, save_ei, OPT_FREE);
  1488.     apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
  1489.                          curbuf->b_fname, TRUE, curbuf);
  1490.     }
  1491.     vim_free(save_ei);
  1492. #endif
  1493. }
  1494.  
  1495. /*
  1496.  * Add files[count] to the arglist of the current window after arg "after".
  1497.  * The file names in files[count] must have been allocated and are taken over.
  1498.  * Files[] itself is not taken over.
  1499.  * Returns index of first added argument.  Returns -1 when failed (out of mem).
  1500.  */
  1501.     static int
  1502. alist_add_list(count, files, after)
  1503.     int        count;
  1504.     char_u    **files;
  1505.     int        after;        /* where to add: 0 = before first one */
  1506. {
  1507.     int        i;
  1508.  
  1509.     if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
  1510.     {
  1511.     if (after < 0)
  1512.         after = 0;
  1513.     if (after > ARGCOUNT)
  1514.         after = ARGCOUNT;
  1515.     if (after < ARGCOUNT)
  1516.         mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
  1517.                        (ARGCOUNT - after) * sizeof(aentry_T));
  1518.     for (i = 0; i < count; ++i)
  1519.     {
  1520.         ARGLIST[after + i].ae_fname = files[i];
  1521.         ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
  1522.     }
  1523.     ALIST(curwin)->al_ga.ga_len += count;
  1524.     ALIST(curwin)->al_ga.ga_room -= count;
  1525.     if (curwin->w_arg_idx >= after)
  1526.         ++curwin->w_arg_idx;
  1527.     return after;
  1528.     }
  1529.  
  1530.     for (i = 0; i < count; ++i)
  1531.     vim_free(files[i]);
  1532.     return -1;
  1533. }
  1534.  
  1535. #endif /* FEAT_LISTCMDS */
  1536.  
  1537. #ifdef FEAT_EVAL
  1538. /*
  1539.  * ":compiler {name}"
  1540.  */
  1541.     void
  1542. ex_compiler(eap)
  1543.     exarg_T    *eap;
  1544. {
  1545.     char_u    *buf;
  1546.  
  1547.     if (*eap->arg == NUL)
  1548.     {
  1549.     /* List all compiler scripts. */
  1550.     do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
  1551.     }
  1552.     else
  1553.     {
  1554.     buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
  1555.     if (buf != NULL)
  1556.     {
  1557.         do_unlet((char_u *)"current_compiler");
  1558.         sprintf((char *)buf, "compiler/%s.vim", eap->arg);
  1559.         (void)cmd_runtime(buf, TRUE);
  1560.         vim_free(buf);
  1561.     }
  1562.     }
  1563. }
  1564. #endif
  1565.  
  1566. /*
  1567.  * ":runtime {name}"
  1568.  */
  1569.     void
  1570. ex_runtime(eap)
  1571.     exarg_T    *eap;
  1572. {
  1573.     cmd_runtime(eap->arg, eap->forceit);
  1574. }
  1575.  
  1576. static void source_callback __ARGS((char_u *fname));
  1577.  
  1578.     static void
  1579. source_callback(fname)
  1580.     char_u    *fname;
  1581. {
  1582.     (void)do_source(fname, FALSE, FALSE);
  1583. }
  1584.  
  1585. /*
  1586.  * Source the file "name" from all directories in 'runtimepath'.
  1587.  * "name" can contain wildcards.
  1588.  * When "all" is TRUE, source all files, otherwise only the first one.
  1589.  * return FAIL when no file could be sourced, OK otherwise.
  1590.  */
  1591.     int
  1592. cmd_runtime(name, all)
  1593.     char_u    *name;
  1594.     int        all;
  1595. {
  1596.     return do_in_runtimepath(name, all, source_callback);
  1597. }
  1598.  
  1599. /*
  1600.  * Find "name" in 'runtimepath'.  When found, call the "callback" function for
  1601.  * it.
  1602.  * When "all" is TRUE repeat for all matches, otherwise only the first one is
  1603.  * used.
  1604.  * Returns OK when at least one match found, FAIL otherwise.
  1605.  */
  1606.     int
  1607. do_in_runtimepath(name, all, callback)
  1608.     char_u    *name;
  1609.     int        all;
  1610.     void    (*callback)__ARGS((char_u *fname));
  1611. {
  1612.     char_u    *rtp;
  1613.     char_u    *np;
  1614.     char_u    *buf;
  1615.     char_u    *tail;
  1616.     int        num_files;
  1617.     char_u    **files;
  1618.     int        i;
  1619.     int        did_one = FALSE;
  1620. #ifdef AMIGA
  1621.     struct Process    *proc = (struct Process *)FindTask(0L);
  1622.     APTR        save_winptr = proc->pr_WindowPtr;
  1623.  
  1624.     /* Avoid a requester here for a volume that doesn't exist. */
  1625.     proc->pr_WindowPtr = (APTR)-1L;
  1626. #endif
  1627.  
  1628.     buf = alloc(MAXPATHL);
  1629.     if (buf != NULL)
  1630.     {
  1631.     if (p_verbose > 1)
  1632.         smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
  1633.                          (char *)name, (char *)p_rtp);
  1634.     /* Loop over all entries in 'runtimepath'. */
  1635.     rtp = p_rtp;
  1636.     while (*rtp != NUL && (all || !did_one))
  1637.     {
  1638.         /* Copy the path from 'runtimepath' to buf[]. */
  1639.         copy_option_part(&rtp, buf, MAXPATHL, ",");
  1640.         if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
  1641.         {
  1642.         add_pathsep(buf);
  1643.         tail = buf + STRLEN(buf);
  1644.  
  1645.         /* Loop over all patterns in "name" */
  1646.         np = name;
  1647.         while (*np != NUL && (all || !did_one))
  1648.         {
  1649.             /* Append the pattern from "name" to buf[]. */
  1650.             copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
  1651.                                        "\t ");
  1652.  
  1653.             if (p_verbose > 2)
  1654.             smsg((char_u *)_("Searching for \"%s\""), (char *)buf);
  1655.             /* Expand wildcards and source each match. */
  1656. #ifdef VMS
  1657.             strcpy((char *)buf, vms_fixfilename(buf));
  1658. #endif
  1659.  
  1660.             if (gen_expand_wildcards(1, &buf, &num_files, &files,
  1661.                                    EW_FILE) == OK)
  1662.             {
  1663.             for (i = 0; i < num_files; ++i)
  1664.             {
  1665.                 (*callback)(files[i]);
  1666.                 did_one = TRUE;
  1667.                 if (!all)
  1668.                 break;
  1669.             }
  1670.             FreeWild(num_files, files);
  1671.             }
  1672.         }
  1673.         }
  1674.     }
  1675.     vim_free(buf);
  1676.     }
  1677.     if (p_verbose > 0 && !did_one)
  1678.     smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
  1679.  
  1680. #ifdef AMIGA
  1681.     proc->pr_WindowPtr = save_winptr;
  1682. #endif
  1683.  
  1684.     return did_one ? OK : FAIL;
  1685. }
  1686.  
  1687. #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
  1688. /*
  1689.  * ":options"
  1690.  */
  1691. /*ARGSUSED*/
  1692.     void
  1693. ex_options(eap)
  1694.     exarg_T    *eap;
  1695. {
  1696.     cmd_source((char_u *)SYS_OPTWIN_FILE, FALSE);
  1697. }
  1698. #endif
  1699.  
  1700. /*
  1701.  * ":source {fname}"
  1702.  */
  1703.     void
  1704. ex_source(eap)
  1705.     exarg_T    *eap;
  1706. {
  1707. #ifdef FEAT_BROWSE
  1708.     if (cmdmod.browse)
  1709.     {
  1710.     char_u *fname = NULL;
  1711.  
  1712.     fname = do_browse(FALSE, (char_u *)_("Run Macro"),
  1713.         NULL, NULL, eap->arg, BROWSE_FILTER_MACROS, curbuf);
  1714.     if (fname != NULL)
  1715.     {
  1716.         cmd_source(fname, eap->forceit);
  1717.         vim_free(fname);
  1718.     }
  1719.     }
  1720.     else
  1721. #endif
  1722.     cmd_source(eap->arg, eap->forceit);
  1723. }
  1724.  
  1725.     static void
  1726. cmd_source(fname, forceit)
  1727.     char_u    *fname;
  1728.     int        forceit;
  1729. {
  1730.     if (*fname == NUL)
  1731.     EMSG(_(e_argreq));
  1732.     else if (forceit)        /* :so! read vi commands */
  1733.     (void)openscript(fname);
  1734.                 /* :so read ex commands */
  1735.     else if (do_source(fname, FALSE, FALSE) == FAIL)
  1736.     EMSG2(_(e_notopen), fname);
  1737. }
  1738.  
  1739. /*
  1740.  * ":source" and associated commands.
  1741.  */
  1742. /*
  1743.  * Structure used to store info for each sourced file.
  1744.  * It is shared between do_source() and getsourceline().
  1745.  * This is required, because it needs to be handed to do_cmdline() and
  1746.  * sourcing can be done recursively.
  1747.  */
  1748. struct source_cookie
  1749. {
  1750.     FILE    *fp;        /* opened file for sourcing */
  1751.     char_u      *nextline;      /* if not NULL: line that was read ahead */
  1752.     int        finished;    /* ":finish" used */
  1753. #if defined (USE_CRNL) || defined (USE_CR)
  1754.     int        fileformat;    /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
  1755.     int        error;        /* TRUE if LF found after CR-LF */
  1756. #endif
  1757. #ifdef FEAT_EVAL
  1758.     linenr_T    breakpoint;    /* next line with breakpoint or zero */
  1759.     char_u    *fname;        /* name of sourced file */
  1760.     int        dbg_tick;    /* debug_tick when breakpoint was set */
  1761. #endif
  1762. #ifdef FEAT_MBYTE
  1763.     vimconv_T    conv;        /* type of conversion */
  1764. #endif
  1765. };
  1766.  
  1767. static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
  1768.  
  1769. #ifdef FEAT_EVAL
  1770. /* Growarray to store the names of sourced scripts. */
  1771. static garray_T script_names = {0, 0, sizeof(char_u *), 4, NULL};
  1772. #define SCRIPT_NAME(id) (((char_u **)script_names.ga_data)[(id) - 1])
  1773. #endif
  1774.  
  1775. /*
  1776.  * do_source: Read the file "fname" and execute its lines as EX commands.
  1777.  *
  1778.  * This function may be called recursively!
  1779.  *
  1780.  * return FAIL if file could not be opened, OK otherwise
  1781.  */
  1782.     int
  1783. do_source(fname, check_other, is_vimrc)
  1784.     char_u    *fname;
  1785.     int        check_other;        /* check for .vimrc and _vimrc */
  1786.     int        is_vimrc;        /* call vimrc_found() when file exists */
  1787. {
  1788.     struct source_cookie    cookie;
  1789.     char_u            *save_sourcing_name;
  1790.     linenr_T            save_sourcing_lnum;
  1791.     char_u            *p;
  1792.     char_u            *fname_exp;
  1793.     int                retval = FAIL;
  1794. #ifdef FEAT_EVAL
  1795.     scid_T            save_current_SID;
  1796.     static scid_T        last_current_SID = 0;
  1797.     void            *save_funccalp;
  1798.     int                save_debug_break_level = debug_break_level;
  1799. #endif
  1800. #ifdef STARTUPTIME
  1801.     struct timeval        tv_rel;
  1802.     struct timeval        tv_start;
  1803. #endif
  1804.  
  1805. #ifdef RISCOS
  1806.     fname_exp = mch_munge_fname(fname);
  1807. #else
  1808.     fname_exp = expand_env_save(fname);
  1809. #endif
  1810.     if (fname_exp == NULL)
  1811.     goto theend;
  1812. #ifdef MACOS_CLASSIC
  1813.     slash_n_colon_adjust(fname_exp);
  1814. #endif
  1815.     if (mch_isdir(fname_exp))
  1816.     {
  1817.     smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
  1818.     goto theend;
  1819.     }
  1820.  
  1821.     cookie.fp = mch_fopen((char *)fname_exp, READBIN);
  1822.     if (cookie.fp == NULL && check_other)
  1823.     {
  1824.     /*
  1825.      * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
  1826.      * and ".exrc" by "_exrc" or vice versa.
  1827.      */
  1828.     p = gettail(fname_exp);
  1829.     if ((*p == '.' || *p == '_')
  1830.         && (STRICMP(p + 1, "vimrc") == 0
  1831.             || STRICMP(p + 1, "gvimrc") == 0
  1832.             || STRICMP(p + 1, "exrc") == 0))
  1833.     {
  1834.         if (*p == '_')
  1835.         *p = '.';
  1836.         else
  1837.         *p = '_';
  1838.         cookie.fp = mch_fopen((char *)fname_exp, READBIN);
  1839.     }
  1840.     }
  1841.  
  1842.     if (cookie.fp == NULL)
  1843.     {
  1844.     if (p_verbose > 0)
  1845.     {
  1846.         if (sourcing_name == NULL)
  1847.         smsg((char_u *)_("could not source \"%s\""), fname);
  1848.         else
  1849.         smsg((char_u *)_("line %ld: could not source \"%s\""),
  1850.             sourcing_lnum, fname);
  1851.     }
  1852.     goto theend;
  1853.     }
  1854.  
  1855.     /*
  1856.      * The file exists.
  1857.      * - In verbose mode, give a message.
  1858.      * - For a vimrc file, may want to set 'compatible', call vimrc_found().
  1859.      */
  1860.     if (p_verbose > 1)
  1861.     {
  1862.     if (sourcing_name == NULL)
  1863.         smsg((char_u *)_("sourcing \"%s\""), fname);
  1864.     else
  1865.         smsg((char_u *)_("line %ld: sourcing \"%s\""),
  1866.             sourcing_lnum, fname);
  1867.     }
  1868.     if (is_vimrc)
  1869.     vimrc_found();
  1870.  
  1871. #ifdef USE_CRNL
  1872.     /* If no automatic file format: Set default to CR-NL. */
  1873.     if (*p_ffs == NUL)
  1874.     cookie.fileformat = EOL_DOS;
  1875.     else
  1876.     cookie.fileformat = EOL_UNKNOWN;
  1877.     cookie.error = FALSE;
  1878. #endif
  1879.  
  1880. #ifdef USE_CR
  1881.     /* If no automatic file format: Set default to CR. */
  1882.     if (*p_ffs == NUL)
  1883.     cookie.fileformat = EOL_MAC;
  1884.     else
  1885.     cookie.fileformat = EOL_UNKNOWN;
  1886.     cookie.error = FALSE;
  1887. #endif
  1888.  
  1889.     cookie.nextline = NULL;
  1890.     cookie.finished = FALSE;
  1891.  
  1892. #ifdef FEAT_EVAL
  1893.     /*
  1894.      * Check if this script has a breakpoint.
  1895.      */
  1896.     cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
  1897.     cookie.fname = fname_exp;
  1898.     cookie.dbg_tick = debug_tick;
  1899. #endif
  1900. #ifdef FEAT_MBYTE
  1901.     cookie.conv.vc_type = CONV_NONE;        /* no conversion */
  1902. # ifdef USE_ICONV
  1903.     cookie.conv.vc_fd = (iconv_t)-1;
  1904. # endif
  1905. #endif
  1906.  
  1907.     /*
  1908.      * Keep the sourcing name/lnum, for recursive calls.
  1909.      */
  1910.     save_sourcing_name = sourcing_name;
  1911.     sourcing_name = fname_exp;
  1912.     save_sourcing_lnum = sourcing_lnum;
  1913.     sourcing_lnum = 0;
  1914.  
  1915. #ifdef STARTUPTIME
  1916.     time_push(&tv_rel, &tv_start);
  1917. #endif
  1918.  
  1919. #ifdef FEAT_EVAL
  1920.     /*
  1921.      * Check if this script was sourced before to finds its SID.
  1922.      * If it's new, generate a new SID.
  1923.      */
  1924.     save_current_SID = current_SID;
  1925.     for (current_SID = script_names.ga_len; current_SID > 0; --current_SID)
  1926.     if (SCRIPT_NAME(current_SID) != NULL
  1927.         && fnamecmp(SCRIPT_NAME(current_SID), fname_exp) == 0)
  1928.         break;
  1929.     if (current_SID == 0)
  1930.     {
  1931.     current_SID = ++last_current_SID;
  1932.     if (ga_grow(&script_names, (int)(current_SID - script_names.ga_len))
  1933.                                     == OK)
  1934.     {
  1935.         while (script_names.ga_len < current_SID)
  1936.         {
  1937.         SCRIPT_NAME(script_names.ga_len + 1) = NULL;
  1938.         ++script_names.ga_len;
  1939.         --script_names.ga_room;
  1940.         }
  1941.         SCRIPT_NAME(current_SID) = fname_exp;
  1942.         fname_exp = NULL;
  1943.     }
  1944.     /* Allocate the local script variables to use for this script. */
  1945.     new_script_vars(current_SID);
  1946.     }
  1947.  
  1948.     /* Don't use local function variables, if called from a function */
  1949.     save_funccalp = save_funccal();
  1950. #endif
  1951.  
  1952.     /*
  1953.      * Call do_cmdline, which will call getsourceline() to get the lines.
  1954.      */
  1955.     do_cmdline(NULL, getsourceline, (void *)&cookie,
  1956.                      DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
  1957.  
  1958.     retval = OK;
  1959.     fclose(cookie.fp);
  1960.     vim_free(cookie.nextline);
  1961.     if (got_int)
  1962.     EMSG(_(e_interr));
  1963.     sourcing_name = save_sourcing_name;
  1964.     sourcing_lnum = save_sourcing_lnum;
  1965. #ifdef FEAT_EVAL
  1966.     current_SID = save_current_SID;
  1967.     restore_funccal(save_funccalp);
  1968. #endif
  1969.     if (p_verbose > 1)
  1970.     {
  1971.     smsg((char_u *)_("finished sourcing %s"), fname);
  1972.     if (sourcing_name != NULL)
  1973.         smsg((char_u *)_("continuing in %s"), sourcing_name);
  1974.     }
  1975. #ifdef STARTUPTIME
  1976.     sprintf(IObuff, "sourcing %s", fname);
  1977.     time_msg(IObuff, &tv_start);
  1978.     time_pop(&tv_rel);
  1979. #endif
  1980.  
  1981. #ifdef FEAT_EVAL
  1982.     /*
  1983.      * After a "finish" in debug mode, need to break at first command of next
  1984.      * sourced file.
  1985.      */
  1986.     if (save_debug_break_level > debug_level
  1987.         && debug_break_level == debug_level)
  1988.     ++debug_break_level;
  1989. #endif
  1990.  
  1991. theend:
  1992.     vim_free(fname_exp);
  1993.     return retval;
  1994. }
  1995.  
  1996. #if defined(FEAT_EVAL) || defined(PROTO)
  1997. /*
  1998.  * ":scriptnames"
  1999.  */
  2000. /*ARGSUSED*/
  2001.     void
  2002. ex_scriptnames(eap)
  2003.     exarg_T    *eap;
  2004. {
  2005.     int i;
  2006.  
  2007.     for (i = 1; i <= script_names.ga_len && !got_int; ++i)
  2008.     if (SCRIPT_NAME(i) != NULL)
  2009.         smsg((char_u *)"%3d: %s", i, SCRIPT_NAME(i));
  2010. }
  2011.  
  2012. /*
  2013.  * Get a pointer to a script name.  Used for ":verbose set".
  2014.  */
  2015.     char_u *
  2016. get_scriptname(id)
  2017.     scid_T    id;
  2018. {
  2019.     if (id == SID_MODELINE)
  2020.     return (char_u *)"modeline";
  2021.     return SCRIPT_NAME(id);
  2022. }
  2023. #endif
  2024.  
  2025. #if defined(USE_CR) || defined(PROTO)
  2026. /*
  2027.  * Version of fgets() which also works for lines ending in a <CR> only
  2028.  * (Macintosh format).
  2029.  */
  2030.     char *
  2031. fgets_cr(s, n, stream)
  2032.     char    *s;
  2033.     int        n;
  2034.     FILE    *stream;
  2035. {
  2036.     int    c = 0;
  2037.     int char_read = 0;
  2038.  
  2039.     while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
  2040.     {
  2041.     c = fgetc(stream);
  2042.     s[char_read++] = c;
  2043.     /* If the file is in DOS format, we need to skip a NL after a CR.  I
  2044.      * thought it was the other way around, but this appears to work... */
  2045.     if (c == '\n')
  2046.     {
  2047.         c = fgetc(stream);
  2048.         if (c != '\r')
  2049.         ungetc(c, stream);
  2050.     }
  2051.     }
  2052.  
  2053.     s[char_read] = 0;
  2054.     if (char_read == 0)
  2055.     return NULL;
  2056.  
  2057.     if (feof(stream) && char_read == 1)
  2058.     return NULL;
  2059.  
  2060.     return s;
  2061. }
  2062. #endif
  2063.  
  2064. /*
  2065.  * Get one full line from a sourced file.
  2066.  * Called by do_cmdline() when it's called from do_source().
  2067.  *
  2068.  * Return a pointer to the line in allocated memory.
  2069.  * Return NULL for end-of-file or some error.
  2070.  */
  2071. /* ARGSUSED */
  2072.     char_u *
  2073. getsourceline(c, cookie, indent)
  2074.     int        c;        /* not used */
  2075.     void    *cookie;
  2076.     int        indent;        /* not used */
  2077. {
  2078.     struct source_cookie *sp = (struct source_cookie *)cookie;
  2079.     char_u        *line;
  2080.     char_u        *p, *s;
  2081.  
  2082. #ifdef FEAT_EVAL
  2083.     /* If breakpoints have been added/deleted need to check for it. */
  2084.     if (sp->dbg_tick < debug_tick)
  2085.     {
  2086.     sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
  2087.     sp->dbg_tick = debug_tick;
  2088.     }
  2089. #endif
  2090.     /*
  2091.      * Get current line.  If there is a read-ahead line, use it, otherwise get
  2092.      * one now.
  2093.      */
  2094.     if (sp->finished)
  2095.     line = NULL;
  2096.     else if (sp->nextline == NULL)
  2097.     line = get_one_sourceline(sp);
  2098.     else
  2099.     {
  2100.     line = sp->nextline;
  2101.     sp->nextline = NULL;
  2102.     ++sourcing_lnum;
  2103.     }
  2104.  
  2105.     /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
  2106.      * contain the 'C' flag. */
  2107.     if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
  2108.     {
  2109.     /* compensate for the one line read-ahead */
  2110.     --sourcing_lnum;
  2111.     for (;;)
  2112.     {
  2113.         sp->nextline = get_one_sourceline(sp);
  2114.         if (sp->nextline == NULL)
  2115.         break;
  2116.         p = skipwhite(sp->nextline);
  2117.         if (*p != '\\')
  2118.         break;
  2119.         s = alloc((int)(STRLEN(line) + STRLEN(p)));
  2120.         if (s == NULL)    /* out of memory */
  2121.         break;
  2122.         STRCPY(s, line);
  2123.         STRCAT(s, p + 1);
  2124.         vim_free(line);
  2125.         line = s;
  2126.         vim_free(sp->nextline);
  2127.     }
  2128.     }
  2129.  
  2130. #ifdef FEAT_MBYTE
  2131.     if (line != NULL && sp->conv.vc_type != CONV_NONE)
  2132.     {
  2133.     /* Convert the encoding of the script line. */
  2134.     s = string_convert(&sp->conv, line, NULL);
  2135.     if (s != NULL)
  2136.     {
  2137.         vim_free(line);
  2138.         line = s;
  2139.     }
  2140.     }
  2141. #endif
  2142.  
  2143. #ifdef FEAT_EVAL
  2144.     /* Did we encounter a breakpoint? */
  2145.     if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
  2146.     {
  2147.     dbg_breakpoint(sp->fname, sourcing_lnum);
  2148.     /* Find next breakpoint. */
  2149.     sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
  2150.     sp->dbg_tick = debug_tick;
  2151.     }
  2152. #endif
  2153.  
  2154.     return line;
  2155. }
  2156.  
  2157.     static char_u *
  2158. get_one_sourceline(sp)
  2159.     struct source_cookie    *sp;
  2160. {
  2161.     garray_T        ga;
  2162.     int            len;
  2163.     int            c;
  2164.     char_u        *buf;
  2165. #ifdef USE_CRNL
  2166.     int            has_cr;        /* CR-LF found */
  2167. #endif
  2168. #ifdef USE_CR
  2169.     char_u        *scan;
  2170. #endif
  2171.     int            have_read = FALSE;
  2172.  
  2173.     /* use a growarray to store the sourced line */
  2174.     ga_init2(&ga, 1, 200);
  2175.  
  2176.     /*
  2177.      * Loop until there is a finished line (or end-of-file).
  2178.      */
  2179.     sourcing_lnum++;
  2180.     for (;;)
  2181.     {
  2182.     /* make room to read at least 80 (more) characters */
  2183.     if (ga_grow(&ga, 80) == FAIL)
  2184.         break;
  2185.     buf = (char_u *)ga.ga_data;
  2186.  
  2187. #ifdef USE_CR
  2188.     if (sp->fileformat == EOL_MAC)
  2189.     {
  2190.         if (fgets_cr((char *)buf + ga.ga_len, ga.ga_room, sp->fp) == NULL
  2191.             || got_int)
  2192.         break;
  2193.     }
  2194.     else
  2195. #endif
  2196.         if (fgets((char *)buf + ga.ga_len, ga.ga_room, sp->fp) == NULL
  2197.             || got_int)
  2198.         break;
  2199.     len = (int)STRLEN(buf);
  2200. #ifdef USE_CRNL
  2201.     /* Ignore a trailing CTRL-Z, when in Dos mode.    Only recognize the
  2202.      * CTRL-Z by its own, or after a NL. */
  2203.     if (       (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
  2204.         && sp->fileformat == EOL_DOS
  2205.         && buf[len - 1] == Ctrl_Z)
  2206.     {
  2207.         buf[len - 1] = NUL;
  2208.         break;
  2209.     }
  2210. #endif
  2211.  
  2212. #ifdef USE_CR
  2213.     /* If the read doesn't stop on a new line, and there's
  2214.      * some CR then we assume a Mac format */
  2215.     if (sp->fileformat == EOL_UNKNOWN)
  2216.     {
  2217.         if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
  2218.         sp->fileformat = EOL_MAC;
  2219.         else
  2220.         sp->fileformat = EOL_UNIX;
  2221.     }
  2222.  
  2223.     if (sp->fileformat == EOL_MAC)
  2224.     {
  2225.         scan = vim_strchr(buf, '\r');
  2226.  
  2227.         if (scan != NULL)
  2228.         {
  2229.         *scan = '\n';
  2230.         if (*(scan + 1) != 0)
  2231.         {
  2232.             *(scan + 1) = 0;
  2233.             fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
  2234.         }
  2235.         }
  2236.         len = STRLEN(buf);
  2237.     }
  2238. #endif
  2239.  
  2240.     have_read = TRUE;
  2241.     ga.ga_room -= len - ga.ga_len;
  2242.     ga.ga_len = len;
  2243.  
  2244.     /* If the line was longer than the buffer, read more. */
  2245.     if (ga.ga_room == 1 && buf[len - 1] != '\n')
  2246.         continue;
  2247.  
  2248.     if (len >= 1 && buf[len - 1] == '\n')    /* remove trailing NL */
  2249.     {
  2250. #ifdef USE_CRNL
  2251.         has_cr = (len >= 2 && buf[len - 2] == '\r');
  2252.         if (sp->fileformat == EOL_UNKNOWN)
  2253.         {
  2254.         if (has_cr)
  2255.             sp->fileformat = EOL_DOS;
  2256.         else
  2257.             sp->fileformat = EOL_UNIX;
  2258.         }
  2259.  
  2260.         if (sp->fileformat == EOL_DOS)
  2261.         {
  2262.         if (has_cr)        /* replace trailing CR */
  2263.         {
  2264.             buf[len - 2] = '\n';
  2265.             --len;
  2266.             --ga.ga_len;
  2267.             ++ga.ga_room;
  2268.         }
  2269.         else        /* lines like ":map xx yy^M" will have failed */
  2270.         {
  2271.             if (!sp->error)
  2272.             EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
  2273.             sp->error = TRUE;
  2274.             sp->fileformat = EOL_UNIX;
  2275.         }
  2276.         }
  2277. #endif
  2278.         /* The '\n' is escaped if there is an odd number of ^V's just
  2279.          * before it, first set "c" just before the 'V's and then check
  2280.          * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
  2281.         for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
  2282.         ;
  2283.         if ((len & 1) != (c & 1))    /* escaped NL, read more */
  2284.         {
  2285.         sourcing_lnum++;
  2286.         continue;
  2287.         }
  2288.  
  2289.         buf[len - 1] = NUL;        /* remove the NL */
  2290.     }
  2291.  
  2292.     /*
  2293.      * Check for ^C here now and then, so recursive :so can be broken.
  2294.      */
  2295.     line_breakcheck();
  2296.     break;
  2297.     }
  2298.  
  2299.     if (have_read)
  2300.     return (char_u *)ga.ga_data;
  2301.  
  2302.     vim_free(ga.ga_data);
  2303.     return NULL;
  2304. }
  2305.  
  2306. /*
  2307.  * ":scriptencoding": Set encoding conversion for a sourced script.
  2308.  * Without the multi-byte feature it's simply ignored.
  2309.  */
  2310. /*ARGSUSED*/
  2311.     void
  2312. ex_scriptencoding(eap)
  2313.     exarg_T    *eap;
  2314. {
  2315. #ifdef FEAT_MBYTE
  2316.     struct source_cookie    *sp;
  2317.     char_u            *name;
  2318.  
  2319.     if (eap->getline != getsourceline)
  2320.     {
  2321.     EMSG(_("E167: :scriptencoding used outside of a sourced file"));
  2322.     return;
  2323.     }
  2324.  
  2325.     if (*eap->arg != NUL)
  2326.     {
  2327.     name = enc_canonize(eap->arg);
  2328.     if (name == NULL)    /* out of memory */
  2329.         return;
  2330.     }
  2331.     else
  2332.     name = eap->arg;
  2333.  
  2334.     /* Setup for conversion from the specified encoding to 'encoding'. */
  2335.     sp = (struct source_cookie *)eap->cookie;
  2336.     convert_setup(&sp->conv, name, p_enc);
  2337.  
  2338.     if (name != eap->arg)
  2339.     vim_free(name);
  2340. #endif
  2341. }
  2342.  
  2343. #if defined(FEAT_EVAL) || defined(PROTO)
  2344. /*
  2345.  * ":finish": Mark a sourced file as finished.
  2346.  */
  2347.     void
  2348. ex_finish(eap)
  2349.     exarg_T    *eap;
  2350. {
  2351.     if (eap->getline == getsourceline)
  2352.     ((struct source_cookie *)eap->cookie)->finished = TRUE;
  2353.     else
  2354.     EMSG(_("E168: :finish used outside of a sourced file"));
  2355. }
  2356.  
  2357. /*
  2358.  * Return TRUE when a sourced file had the ":finish" command: Don't give error
  2359.  * message for missing ":endif".
  2360.  */
  2361.     int
  2362. source_finished(cookie)
  2363.     void    *cookie;
  2364. {
  2365.     return ((struct source_cookie *)cookie)->finished == TRUE;
  2366. }
  2367. #endif
  2368.  
  2369. #if defined(FEAT_LISTCMDS) || defined(PROTO)
  2370. /*
  2371.  * ":checktime [buffer]"
  2372.  */
  2373.     void
  2374. ex_checktime(eap)
  2375.     exarg_T    *eap;
  2376. {
  2377.     buf_T    *buf;
  2378.  
  2379.     if (eap->addr_count == 0)    /* default is all buffers */
  2380.     check_timestamps(FALSE);
  2381.     else
  2382.     {
  2383.     buf = buflist_findnr((int)eap->line2);
  2384.     if (buf != NULL)    /* cannot happen? */
  2385.         (void)buf_check_timestamp(buf, FALSE);
  2386.     }
  2387. }
  2388. #endif
  2389.  
  2390. #if defined(FEAT_PRINTER) || defined(PROTO)
  2391. /*
  2392.  * Printing code (Machine-independent.)
  2393.  * To implement printing on a platform, the following functions must be
  2394.  * defined:
  2395.  *
  2396.  * int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
  2397.  * Called once.  Code should display printer dialogue (if appropriate) and
  2398.  * determine printer font and margin settings.  Reset has_color if the printer
  2399.  * doesn't support colors at all.
  2400.  * Returns FAIL to abort.
  2401.  *
  2402.  * int mch_print_begin(prt_settings_T *settings)
  2403.  * Called to start the print job.
  2404.  * Return FALSE to abort.
  2405.  *
  2406.  * int mch_print_begin_page(char_u *msg)
  2407.  * Called at the start of each page.
  2408.  * "msg" indicates the progress of the print job, can be NULL.
  2409.  * Return FALSE to abort.
  2410.  *
  2411.  * int mch_print_end_page()
  2412.  * Called at the end of each page.
  2413.  * Return FALSE to abort.
  2414.  *
  2415.  * int mch_print_blank_page()
  2416.  * Called to generate a blank page for collated, duplex, multiple copy
  2417.  * document.  Return FALSE to abort.
  2418.  *
  2419.  * void mch_print_end(prt_settings_T *psettings)
  2420.  * Called at normal end of print job.
  2421.  *
  2422.  * void mch_print_cleanup()
  2423.  * Called if print job ends normally or is abandoned. Free any memory, close
  2424.  * devices and handles.  Also called when mch_print_begin() fails, but not
  2425.  * when mch_print_init() fails.
  2426.  *
  2427.  * void mch_print_set_font(int Bold, int Italic, int Underline);
  2428.  * Called whenever the font style changes.
  2429.  *
  2430.  * void mch_print_set_bg(long bgcol);
  2431.  * Called to set the background color for the following text. Parameter is an
  2432.  * RGB value.
  2433.  *
  2434.  * void mch_print_set_fg(long fgcol);
  2435.  * Called to set the foreground color for the following text. Parameter is an
  2436.  * RGB value.
  2437.  *
  2438.  * mch_print_start_line(int margin, int page_line)
  2439.  * Sets the current position at the start of line "page_line".
  2440.  * If margin is TRUE start in the left margin (for header and line number).
  2441.  *
  2442.  * int mch_print_text_out(char_u *p, int len);
  2443.  * Output one character of text p[len] at the current position.
  2444.  * Return TRUE if there is no room for another character in the same line.
  2445.  *
  2446.  * Note that the generic code has no idea of margins. The machine code should
  2447.  * simply make the page look smaller!  The header and the line numbers are
  2448.  * printed in the margin.
  2449.  */
  2450.  
  2451. #ifdef FEAT_SYN_HL
  2452. static const long_u  cterm_color_8[8] =
  2453. {
  2454.     (long_u)0x000000, (long_u)0xff0000, (long_u)0x00ff00, (long_u)0xffff00,
  2455.     (long_u)0x0000ff, (long_u)0xff00ff, (long_u)0x00ffff, (long_u)0xffffff
  2456. };
  2457.  
  2458. static const long_u  cterm_color_16[16] =
  2459. {
  2460.     (long_u)0x000000, (long_u)0x0000c0, (long_u)0x008000, (long_u)0x004080,
  2461.     (long_u)0xc00000, (long_u)0xc000c0, (long_u)0x808000, (long_u)0xc0c0c0,
  2462.     (long_u)0x808080, (long_u)0x6060ff, (long_u)0x00ff00, (long_u)0x00ffff,
  2463.     (long_u)0xff8080, (long_u)0xff40ff, (long_u)0xffff00, (long_u)0xffffff
  2464. };
  2465.  
  2466. static int        current_syn_id;
  2467. #endif
  2468.  
  2469. #define COLOR_BLACK    (long_u)0
  2470. #define COLOR_WHITE    (long_u)0xFFFFFF
  2471.  
  2472. static int    curr_italic;
  2473. static int    curr_bold;
  2474. static int    curr_underline;
  2475. static long_u    curr_bg;
  2476. static long_u    curr_fg;
  2477. static int    page_count;
  2478.  
  2479. /*
  2480.  * These values determine the print position on a page.
  2481.  */
  2482. typedef struct
  2483. {
  2484.     int        lead_spaces;        /* remaining spaces for a TAB */
  2485.     int        print_pos;        /* virtual column for computing TABs */
  2486.     colnr_T    column;            /* byte column */
  2487.     linenr_T    file_line;        /* line nr in the buffer */
  2488.     long_u    bytes_printed;        /* bytes printed so far */
  2489. } prt_pos_T;
  2490.  
  2491. static long_u darken_rgb __ARGS((long_u rgb));
  2492. static long_u prt_get_term_color __ARGS((int colorindex));
  2493. static void prt_set_fg __ARGS((long_u fg));
  2494. static void prt_set_bg __ARGS((long_u bg));
  2495. static void prt_set_font __ARGS((int bold, int italic, int underline));
  2496. static void prt_line_number __ARGS((prt_settings_T *psettings, int page_line, linenr_T lnum));
  2497. static void prt_header __ARGS((prt_settings_T *psettings, int pagenum, linenr_T lnum));
  2498. static void prt_message __ARGS((char_u *s));
  2499. static colnr_T hardcopy_line __ARGS((prt_settings_T *psettings, int page_line, prt_pos_T *ppos));
  2500.  
  2501. /*
  2502.  * If using a dark background, the colors will probably be too bright to show
  2503.  * up well on white paper, so reduce their brightness.
  2504.  */
  2505.     static long_u
  2506. darken_rgb(rgb)
  2507.     long_u    rgb;
  2508. {
  2509.     return    ((rgb >> 17) << 16)
  2510.         +    (((rgb & 0xff00) >> 9) << 8)
  2511.         +    ((rgb & 0xff) >> 1);
  2512. }
  2513.  
  2514.     static long_u
  2515. prt_get_term_color(colorindex)
  2516.     int        colorindex;
  2517. {
  2518.     /* TODO: Should check for xterm with 88 or 256 colors. */
  2519.     if (t_colors > 8)
  2520.     return cterm_color_16[colorindex % 16];
  2521.     return cterm_color_8[colorindex % 8];
  2522. }
  2523.  
  2524.     static void
  2525. prt_set_fg(fg)
  2526.     long_u fg;
  2527. {
  2528.     if (fg != curr_fg)
  2529.     {
  2530.     curr_fg = fg;
  2531.     mch_print_set_fg(fg);
  2532.     }
  2533. }
  2534.  
  2535.     static void
  2536. prt_set_bg(bg)
  2537.     long_u bg;
  2538. {
  2539.     if (bg != curr_bg)
  2540.     {
  2541.     curr_bg = bg;
  2542.     mch_print_set_bg(bg);
  2543.     }
  2544. }
  2545.  
  2546.     static void
  2547. prt_set_font(bold, italic, underline)
  2548.     int        bold;
  2549.     int        italic;
  2550.     int        underline;
  2551. {
  2552.     if (curr_bold != bold
  2553.         || curr_italic != italic
  2554.         || curr_underline != underline)
  2555.     {
  2556.     curr_underline = underline;
  2557.     curr_italic = italic;
  2558.     curr_bold = bold;
  2559.     mch_print_set_font(bold, italic, underline);
  2560.     }
  2561. }
  2562.  
  2563. /*
  2564.  * Print the line number in the left margin.
  2565.  */
  2566.     static void
  2567. prt_line_number(psettings, page_line, lnum)
  2568.     prt_settings_T *psettings;
  2569.     int        page_line;
  2570.     linenr_T    lnum;
  2571. {
  2572.     int        i;
  2573.     char_u    tbuf[20];
  2574.  
  2575.     if (psettings->has_color)
  2576.     prt_set_fg((long_u)0x808080);
  2577.     else
  2578.     prt_set_fg(COLOR_BLACK);
  2579.     prt_set_bg(COLOR_WHITE);
  2580.     prt_set_font(FALSE, TRUE, FALSE);
  2581.     mch_print_start_line(TRUE, page_line);
  2582.  
  2583.     /* Leave two spaces between the number and the text; depends on
  2584.      * PRINT_NUMBER_WIDTH. */
  2585.     sprintf((char *)tbuf, "%6ld", (long)lnum);
  2586.     for (i = 0; i < 6; i++)
  2587.     (void)mch_print_text_out(&tbuf[i], 1);
  2588.  
  2589. #ifdef FEAT_SYN_HL
  2590.     if (psettings->do_syntax)
  2591.     /* Set colors for next character. */
  2592.     current_syn_id = -1;
  2593.     else
  2594. #endif
  2595.     {
  2596.     /* Set colors and font back to normal. */
  2597.     prt_set_fg(COLOR_BLACK);
  2598.     prt_set_bg(COLOR_WHITE);
  2599.     prt_set_font(FALSE, FALSE, FALSE);
  2600.     }
  2601. }
  2602.  
  2603. static linenr_T printer_page_num;
  2604.  
  2605.     int
  2606. get_printer_page_num()
  2607. {
  2608.     return printer_page_num;
  2609. }
  2610.  
  2611. /*
  2612.  * Get the currently effective header height.
  2613.  */
  2614.     int
  2615. prt_header_height()
  2616. {
  2617.     if (printer_opts[OPT_PRINT_HEADERHEIGHT].present)
  2618.     return printer_opts[OPT_PRINT_HEADERHEIGHT].number;
  2619.     return 2;
  2620. }
  2621.  
  2622. /*
  2623.  * Return TRUE if using a line number for printing.
  2624.  */
  2625.     int
  2626. prt_use_number()
  2627. {
  2628.     return (printer_opts[OPT_PRINT_NUMBER].present
  2629.         && TO_LOWER(printer_opts[OPT_PRINT_NUMBER].string[0]) == 'y');
  2630. }
  2631.  
  2632. /*
  2633.  * Return the unit used in a margin item in 'printoptions'.
  2634.  * Returns PRT_UNIT_NONE if not recognized.
  2635.  */
  2636.     int
  2637. prt_get_unit(idx)
  2638.     int        idx;
  2639. {
  2640.     int        u = PRT_UNIT_NONE;
  2641.     int        i;
  2642.     static char *(units[4]) = PRT_UNIT_NAMES;
  2643.  
  2644.     if (printer_opts[idx].present)
  2645.     for (i = 0; i < 4; ++i)
  2646.         if (STRNICMP(printer_opts[idx].string, units[i], 2) == 0)
  2647.         {
  2648.         u = i;
  2649.         break;
  2650.         }
  2651.     return u;
  2652. }
  2653.  
  2654. /*
  2655.  * Print the page header.
  2656.  */
  2657. /*ARGSUSED*/
  2658.     static void
  2659. prt_header(psettings, pagenum, lnum)
  2660.     prt_settings_T  *psettings;
  2661.     int        pagenum;
  2662.     linenr_T    lnum;
  2663. {
  2664.     int        width = psettings->chars_per_line;
  2665.     int        page_line;
  2666.     char_u    *tbuf;
  2667.     char_u    *p;
  2668. #ifdef FEAT_MBYTE
  2669.     int        l;
  2670. #endif
  2671.  
  2672.     /* Also use the space for the line number. */
  2673.     if (prt_use_number())
  2674.     width += PRINT_NUMBER_WIDTH;
  2675.  
  2676.     tbuf = alloc(width + IOSIZE);
  2677.     if (tbuf == NULL)
  2678.     return;
  2679.  
  2680. #ifdef FEAT_STL_OPT
  2681.     if (*p_header != NUL)
  2682.     {
  2683.     linenr_T    tmp_lnum, tmp_topline, tmp_botline;
  2684.  
  2685.     /*
  2686.      * Need to (temporarily) set current line number and first/last line
  2687.      * number on the 'window'.  Since we don't know how long the page is,
  2688.      * set the first and current line number to the top line, and guess
  2689.      * that the page length is 64.
  2690.      */
  2691.     tmp_lnum = curwin->w_cursor.lnum;
  2692.     tmp_topline = curwin->w_topline;
  2693.     tmp_botline = curwin->w_botline;
  2694.     curwin->w_cursor.lnum = lnum;
  2695.     curwin->w_topline = lnum;
  2696.     curwin->w_botline = lnum + 63;
  2697.     printer_page_num = pagenum;
  2698.  
  2699.     build_stl_str_hl(curwin, tbuf, p_header, ' ', width, NULL);
  2700.  
  2701.     /* Reset line numbers */
  2702.     curwin->w_cursor.lnum = tmp_lnum;
  2703.     curwin->w_topline = tmp_topline;
  2704.     curwin->w_botline = tmp_botline;
  2705.     }
  2706.     else
  2707. #endif
  2708.     sprintf((char *)tbuf, "Page %d", pagenum);
  2709.  
  2710.     prt_set_fg(COLOR_BLACK);
  2711.     prt_set_bg(COLOR_WHITE);
  2712.     prt_set_font(TRUE, FALSE, FALSE);
  2713.  
  2714.     /* Use a negative line number to indicate printing in the top margin. */
  2715.     page_line = 0 - prt_header_height();
  2716.     mch_print_start_line(TRUE, page_line);
  2717.     for (p = tbuf; *p != NUL; )
  2718.     {
  2719.     if (mch_print_text_out(p,
  2720. #ifdef FEAT_MBYTE
  2721.         (l = (*mb_ptr2len_check)(p))
  2722. #else
  2723.         1
  2724. #endif
  2725.             ))
  2726.     {
  2727.         ++page_line;
  2728.         if (page_line >= 0) /* out of room in header */
  2729.         break;
  2730.         mch_print_start_line(TRUE, page_line);
  2731.     }
  2732. #ifdef FEAT_MBYTE
  2733.     p += l;
  2734. #else
  2735.     p++;
  2736. #endif
  2737.     }
  2738.  
  2739.     vim_free(tbuf);
  2740.  
  2741. #ifdef FEAT_SYN_HL
  2742.     if (psettings->do_syntax)
  2743.     /* Set colors for next character. */
  2744.     current_syn_id = -1;
  2745.     else
  2746. #endif
  2747.     {
  2748.     /* Set colors and font back to normal. */
  2749.     prt_set_fg(COLOR_BLACK);
  2750.     prt_set_bg(COLOR_WHITE);
  2751.     prt_set_font(FALSE, FALSE, FALSE);
  2752.     }
  2753. }
  2754.  
  2755. /*
  2756.  * Display a print status message.
  2757.  */
  2758.     static void
  2759. prt_message(s)
  2760.     char_u    *s;
  2761. {
  2762.     screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
  2763.     screen_puts(s, (int)Rows - 1, 0, hl_attr(HLF_R));
  2764.     out_flush();
  2765. }
  2766.  
  2767.     void
  2768. ex_hardcopy(eap)
  2769.     exarg_T    *eap;
  2770. {
  2771.     linenr_T        lnum;
  2772.     int            collated_copies, uncollated_copies;
  2773.     prt_settings_T    settings;
  2774.     long_u        bytes_to_print = 0;
  2775.     int            page_line;
  2776.     int            jobsplit;
  2777.  
  2778.     memset(&settings, 0, sizeof(prt_settings_T));
  2779.     settings.has_color = TRUE;
  2780.  
  2781. # ifdef FEAT_POSTSCRIPT
  2782.     if (*eap->arg == '>')
  2783.     settings.outfile = skipwhite(eap->arg + 1);
  2784.     else if (*eap->arg != NUL)
  2785.     settings.arguments = eap->arg;
  2786. # endif
  2787.  
  2788.     /*
  2789.      * Initialise for printing.  Ask the user for settings, unless forceit is
  2790.      * set.
  2791.      * The mch_print_init() code should set up margins if applicable. (It may
  2792.      * not be a real printer - for example the engine might generate HTML or
  2793.      * PS.)
  2794.      */
  2795.     if (mch_print_init(&settings,
  2796.             curbuf->b_fname == NULL
  2797.                 ? (char_u *)buf_spname(curbuf)
  2798.                 : curbuf->b_sfname == NULL
  2799.                 ? curbuf->b_fname
  2800.                 : curbuf->b_sfname,
  2801.             eap->forceit) == FAIL)
  2802.     return;
  2803.  
  2804. #ifdef FEAT_SYN_HL
  2805.     if (printer_opts[OPT_PRINT_SYNTAX].present
  2806.         && TO_LOWER(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a')
  2807.     settings.do_syntax =
  2808.           (TO_LOWER(printer_opts[OPT_PRINT_SYNTAX].string[0]) == 'y');
  2809.     else
  2810.     settings.do_syntax = settings.has_color;
  2811. #endif
  2812.  
  2813.     /*
  2814.      * Estimate the total lines to be printed
  2815.      */
  2816.     for (lnum = eap->line1; lnum <= eap->line2; lnum++)
  2817.     bytes_to_print += (long_u)STRLEN(skipwhite(ml_get(lnum)));
  2818.     if (bytes_to_print == 0)
  2819.     {
  2820.     MSG(_("No text to be printed"));
  2821.     goto print_fail_no_begin;
  2822.     }
  2823.  
  2824.     /* Set colors and font to normal. */
  2825.     curr_bg = (long_u)0xffffffff;
  2826.     curr_fg = (long_u)0xffffffff;
  2827.     curr_italic = MAYBE;
  2828.     curr_bold = MAYBE;
  2829.     curr_underline = MAYBE;
  2830.  
  2831.     prt_set_fg(COLOR_BLACK);
  2832.     prt_set_bg(COLOR_WHITE);
  2833.     prt_set_font(FALSE, FALSE, FALSE);
  2834. #ifdef FEAT_SYN_HL
  2835.     current_syn_id = -1;
  2836. #endif
  2837.  
  2838.     jobsplit = (printer_opts[OPT_PRINT_JOBSPLIT].present
  2839.           && TO_LOWER(printer_opts[OPT_PRINT_JOBSPLIT].string[0]) == 'y');
  2840.  
  2841.     if (!mch_print_begin(&settings))
  2842.     goto print_fail_no_begin;
  2843.  
  2844.     /*
  2845.      * Loop over collated copies: 1 2 3, 1 2 3, ...
  2846.      */
  2847.     page_count = 0;
  2848.     for (collated_copies = 0;
  2849.         collated_copies < settings.n_collated_copies;
  2850.         collated_copies++)
  2851.     {
  2852.     prt_pos_T    prtpos;        /* current print position */
  2853.     prt_pos_T    page_prtpos;    /* print position at page start */
  2854.     int        side;
  2855.  
  2856.     memset(&page_prtpos, 0, sizeof(prt_pos_T));
  2857.     page_prtpos.file_line = eap->line1;
  2858.     prtpos = page_prtpos;
  2859.  
  2860.     if (jobsplit && collated_copies > 0)
  2861.     {
  2862.         /* Splitting jobs: Stop a previous job and start a new one. */
  2863.         mch_print_end(&settings);
  2864.         if (!mch_print_begin(&settings))
  2865.         goto print_fail_no_begin;
  2866.     }
  2867.  
  2868.     /*
  2869.      * Loop over all pages in the print job: 1 2 3 ...
  2870.      */
  2871.     for (page_count = 0; prtpos.file_line <= eap->line2; ++page_count)
  2872.     {
  2873.         /*
  2874.          * Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ...
  2875.          * For duplex: 12 12 12 34 34 34, ...
  2876.          */
  2877.         for (uncollated_copies = 0;
  2878.             uncollated_copies < settings.n_uncollated_copies;
  2879.             uncollated_copies++)
  2880.         {
  2881.         /* Set the print position to the start of this page. */
  2882.         prtpos = page_prtpos;
  2883.  
  2884.         /*
  2885.          * Do front and rear side of a page.
  2886.          */
  2887.         for (side = 0; side <= settings.duplex; ++side)
  2888.         {
  2889.             /*
  2890.              * Print one page.
  2891.              */
  2892.  
  2893.             /* Check for interrupt character every page. */
  2894.             ui_breakcheck();
  2895.             if (got_int || settings.user_abort)
  2896.             goto print_fail;
  2897.  
  2898.             sprintf((char *)IObuff, _("Printing page %d (%d%%)"),
  2899.                 page_count + 1 + side,
  2900.                 (int)((prtpos.bytes_printed * 100)
  2901.                                / bytes_to_print));
  2902.             if (!mch_print_begin_page(IObuff))
  2903.             goto print_fail;
  2904.  
  2905.             if (settings.n_collated_copies > 1)
  2906.             sprintf((char *)IObuff + STRLEN(IObuff),
  2907.                 _(" Copy %d of %d"),
  2908.                 collated_copies + 1,
  2909.                 settings.n_collated_copies);
  2910.             prt_message(IObuff);
  2911.  
  2912.             /*
  2913.              * Output header if required
  2914.              */
  2915.             if (prt_header_height() > 0)
  2916.             prt_header(&settings, page_count + 1 + side,
  2917.                             prtpos.file_line);
  2918.  
  2919.             for (page_line = 0; page_line < settings.lines_per_page;
  2920.                                   ++page_line)
  2921.             {
  2922.             prtpos.column = hardcopy_line(&settings,
  2923.                               page_line, &prtpos);
  2924.             if (prtpos.column == 0)
  2925.             {
  2926.                 /* finished a file line */
  2927.                 prtpos.bytes_printed +=
  2928.                   STRLEN(skipwhite(ml_get(prtpos.file_line)));
  2929.                 if (++prtpos.file_line > eap->line2)
  2930.                 break; /* reached the end */
  2931.             }
  2932.             }
  2933.  
  2934.             if (!mch_print_end_page())
  2935.             goto print_fail;
  2936.             if (prtpos.file_line > eap->line2)
  2937.             break; /* reached the end */
  2938.         }
  2939.  
  2940.         /*
  2941.          * Extra blank page for duplexing with odd number of pages and
  2942.          * more copies to come.
  2943.          */
  2944.         if (prtpos.file_line > eap->line2 && settings.duplex
  2945.                                  && side == 0
  2946.             && uncollated_copies + 1 < settings.n_uncollated_copies)
  2947.         {
  2948.             if (!mch_print_blank_page())
  2949.             goto print_fail;
  2950.         }
  2951.         }
  2952.         if (settings.duplex && prtpos.file_line <= eap->line2)
  2953.         ++page_count;
  2954.  
  2955.         /* Remember the position where the next page starts. */
  2956.         page_prtpos = prtpos;
  2957.     }
  2958.  
  2959.     sprintf((char *)IObuff, _("Printed: %s"), settings.jobname);
  2960.     prt_message(IObuff);
  2961.     }
  2962.  
  2963. print_fail:
  2964.     if (got_int || settings.user_abort)
  2965.     {
  2966.     sprintf((char *)IObuff, _("Printing aborted"));
  2967.     prt_message(IObuff);
  2968.     }
  2969.     mch_print_end(&settings);
  2970.  
  2971. print_fail_no_begin:
  2972.     mch_print_cleanup();
  2973. }
  2974.  
  2975. /*
  2976.  * Print one page line.
  2977.  * Return the next column to print, or zero if the line is finished.
  2978.  */
  2979.     static colnr_T
  2980. hardcopy_line(psettings, page_line, ppos)
  2981.     prt_settings_T    *psettings;
  2982.     int            page_line;
  2983.     prt_pos_T        *ppos;
  2984. {
  2985.     colnr_T    col;
  2986.     char_u    *line;
  2987.     int        need_break = FALSE;
  2988.     int        outputlen;
  2989.     int        colorindex;
  2990.     char    *color;
  2991.     int        id;
  2992.     int        tab_spaces;
  2993.     long_u    print_pos;
  2994.     long_u    this_color;
  2995. #ifdef FEAT_SYN_HL
  2996.     char    modec;
  2997. #endif
  2998.  
  2999.     if (ppos->column == 0)
  3000.     {
  3001.     print_pos = 0;
  3002.     tab_spaces = 0;
  3003.     }
  3004.     else
  3005.     {
  3006.     /* left over from wrap halfway a tab */
  3007.     print_pos = ppos->print_pos;
  3008.     tab_spaces = ppos->lead_spaces;
  3009.     }
  3010.  
  3011. #ifdef FEAT_SYN_HL
  3012. # ifdef  FEAT_GUI
  3013.     if (gui.in_use)
  3014.     modec = 'g';
  3015.     else
  3016. # endif
  3017.     if (t_colors > 1)
  3018.         modec = 'c';
  3019.     else
  3020.         modec = 't';
  3021. #endif
  3022.  
  3023.     if (prt_use_number() && ppos->column == 0)
  3024.     prt_line_number(psettings, page_line, ppos->file_line);
  3025.  
  3026.     mch_print_start_line(0, page_line);
  3027.     line = ml_get(ppos->file_line);
  3028.  
  3029.     /*
  3030.      * Loop over the columns until the end of the file line or right margin.
  3031.      */
  3032.     for (col = ppos->column; line[col] != NUL && !need_break; col += outputlen)
  3033.     {
  3034.     outputlen = 1;
  3035. #ifdef FEAT_MBYTE
  3036.     if (has_mbyte && (outputlen = (*mb_ptr2len_check)(line + col)) < 1)
  3037.         outputlen = 1;
  3038. #endif
  3039. #ifdef FEAT_SYN_HL
  3040.     /*
  3041.      * syntax highlighting stuff.
  3042.      */
  3043.     if (psettings->do_syntax)
  3044.     {
  3045.         id = syn_get_id(ppos->file_line, (long)col, 1);
  3046.         if (id > 0)
  3047.         id = syn_get_final_id(id);
  3048.         else
  3049.         id = 0;
  3050.         /* Get the line again, a multi-line regexp may invalidate it. */
  3051.         line = ml_get(ppos->file_line);
  3052.  
  3053.         if (id != current_syn_id)
  3054.         {
  3055.         current_syn_id = id;
  3056.  
  3057.         prt_set_font((highlight_has_attr(id, HL_BOLD, modec) != NULL),
  3058.             (highlight_has_attr(id, HL_ITALIC, modec) != NULL),
  3059.             (highlight_has_attr(id, HL_UNDERLINE, modec) != NULL));
  3060.  
  3061. # ifdef FEAT_GUI
  3062.         if (gui.in_use)
  3063.         {
  3064.             this_color = highlight_gui_color_rgb(id, FALSE);
  3065.             if (this_color == COLOR_BLACK)
  3066.             this_color = COLOR_WHITE;
  3067.             prt_set_bg(this_color);
  3068.  
  3069.             this_color = highlight_gui_color_rgb(id, TRUE);
  3070.             if (this_color == COLOR_WHITE)
  3071.             this_color = COLOR_BLACK;
  3072.             else if (*p_bg == 'd')
  3073.             this_color = darken_rgb(this_color);
  3074.             prt_set_fg(this_color);
  3075.         }
  3076.         else
  3077. # endif
  3078.         {
  3079.             color = (char *)highlight_color(id, (char_u *)"fg", modec);
  3080.             if (color == NULL)
  3081.             colorindex = 0;
  3082.             else
  3083.             colorindex = atoi(color);
  3084.  
  3085.             if (colorindex >= 0 && colorindex < t_colors)
  3086.             {
  3087.             this_color = prt_get_term_color(colorindex);
  3088.             if (this_color == COLOR_WHITE)
  3089.                 this_color = COLOR_BLACK;
  3090.             else if (*p_bg == 'd')
  3091.                 this_color = darken_rgb(this_color);
  3092.             prt_set_fg(this_color);
  3093.             }
  3094.             else
  3095.             prt_set_fg(COLOR_BLACK);
  3096.         }
  3097.         }
  3098.     }
  3099. #endif /* FEAT_SYN_HL */
  3100.  
  3101.     /*
  3102.      * Appropriately expand any tabs to spaces.
  3103.      */
  3104.     if (line[col] == TAB || tab_spaces != 0)
  3105.     {
  3106.         if (tab_spaces == 0)
  3107.         tab_spaces = curbuf->b_p_ts - (print_pos % curbuf->b_p_ts);
  3108.  
  3109.         while (tab_spaces > 0)
  3110.         {
  3111.         need_break = mch_print_text_out((char_u *)" ", 1);
  3112.         print_pos++;
  3113.         tab_spaces--;
  3114.         if (need_break)
  3115.             break;
  3116.         }
  3117.         /* Keep the TAB if we didn't finish it. */
  3118.         if (need_break && tab_spaces > 0)
  3119.         break;
  3120.     }
  3121.     else
  3122.     {
  3123.         need_break = mch_print_text_out(line + col, outputlen);
  3124.         print_pos++;
  3125.     }
  3126.     }
  3127.  
  3128.     ppos->lead_spaces = tab_spaces;
  3129.     ppos->print_pos = print_pos;
  3130.  
  3131.     /*
  3132.      * Start next line of file if we clip lines, or have reached end of the
  3133.      * line.
  3134.      */
  3135.     if (line[col] == NUL || (printer_opts[OPT_PRINT_WRAP].present
  3136.           && TO_LOWER(printer_opts[OPT_PRINT_WRAP].string[0]) == 'n'))
  3137.     return 0;
  3138.     return col;
  3139. }
  3140.  
  3141. # if defined(FEAT_POSTSCRIPT) || defined(PROTO)
  3142.  
  3143. /*
  3144.  * PS printer stuff.
  3145.  *
  3146.  * Sources of information to help maintain the PS printing code:
  3147.  *
  3148.  * 1. PostScript Language Reference, 3rd Edition,
  3149.  *      Addison-Wesley, 1999, ISBN 0-201-37922-8
  3150.  * 2. PostScript Language Program Design,
  3151.  *      Addison-Wesley, 1988, ISBN 0-201-14396-8
  3152.  * 3. PostScript Tutorial and Cookbook,
  3153.  *      Addison Wesley, 1985, ISBN 0-201-10179-3
  3154.  * 4. PostScript Language Document Structuring Conventions Specification,
  3155.  *    version 3.0,
  3156.  *      Adobe Technote 5001, 25th September 1992
  3157.  * 5. PostScript Printer Description File Format Specification, Version 4.3,
  3158.  *      Adobe technote 5003, 9th February 1996
  3159.  * 6. Adobe Font Metrics File Format Specification, Version 4.1,
  3160.  *      Adobe Technote 5007, 7th October 1998
  3161.  *
  3162.  * Some of these documents can be found in PDF form on Adobe's web site -
  3163.  * http://www.adobe.com
  3164.  */
  3165.  
  3166. #define PRT_PS_DEFAULT_DPI        (72)    /* Default user space resolution */
  3167. #define PRT_PS_DEFAULT_FONTSIZE     (10)
  3168. #define PRT_PS_DEFAULT_BUFFER_SIZE  (80)
  3169.  
  3170. struct prt_mediasize_S
  3171. {
  3172.     char    *name;
  3173.     float    width;        /* width and height in points for portrait */
  3174.     float    height;
  3175. };
  3176.  
  3177. #define PRT_MEDIASIZE_LEN  (sizeof(prt_mediasize) / sizeof(struct prt_mediasize_S))
  3178.  
  3179. static struct prt_mediasize_S prt_mediasize[] =
  3180. {
  3181.     {"A4",        595.0,  842.0},
  3182.     {"letter",        612.0,  792.0},
  3183.     {"10x14",        720.0, 1008.0},
  3184.     {"A3",        842.0, 1191.0},
  3185.     {"A5",        420.0,  595.0},
  3186.     {"B4",        729.0, 1032.0},
  3187.     {"B5",        516.0,  729.0},
  3188.     {"executive",    522.0,  756.0},
  3189.     {"folio",        595.0,  935.0},
  3190.     {"ledger",           1224.0,  792.0},   /* Yes, it is wider than taller! */
  3191.     {"legal",        612.0, 1008.0},
  3192.     {"quarto",        610.0,  780.0},
  3193.     {"statement",    396.0,  612.0},
  3194.     {"tabloid",        792.0, 1224.0}
  3195. };
  3196.  
  3197. /* PS font names, must be in Roman, Bold, Italic, Bold-Italic order */
  3198. struct prt_ps_font_S
  3199. {
  3200.     int        wx;
  3201.     int        uline_offset;
  3202.     int        uline_width;
  3203.     int        bbox_min_y;
  3204.     int        bbox_max_y;
  3205.     char    *(ps_fontname[4]);
  3206. };
  3207.  
  3208. #define PRT_PS_FONT_ROMAN    (0)
  3209. #define PRT_PS_FONT_BOLD    (1)
  3210. #define PRT_PS_FONT_OBLIQUE    (2)
  3211. #define PRT_PS_FONT_BOLDOBLIQUE (3)
  3212.  
  3213. static struct prt_ps_font_S prt_ps_font =
  3214. {
  3215.     600,
  3216.     -100, 50,
  3217.     -250, 805,
  3218.     {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"}
  3219. };
  3220.  
  3221. #define PRT_RESOURCE_PROLOG        "VIM-Prolog 1.2 0"
  3222.  
  3223. #if defined(WIN32)
  3224. #define PRT_RESOURCE_ENCODING        "VIM-Encoding-Windows 1.0 0"
  3225. #define PRT_RESOURCE_ENCODING_FILE    "evwin.ps"
  3226. #else /* !WIN32 */
  3227. #if defined(MACOS)
  3228. #define PRT_RESOURCE_ENCODING        "VIM-Encoding-Macintosh 1.0 0"
  3229. #define PRT_RESOURCE_ENCODING_FILE    "evmac.ps"
  3230. #else /* !MACOS */
  3231. #if defined(VMS)
  3232. #define PRT_RESOURCE_ENCODING        "VIM-Encoding-VMS 1.0 0"
  3233. #define PRT_RESOURCE_ENCODING_FILE    "evvms.ps"
  3234. #else /* !VMS */
  3235. #if defined(EBCDIC)
  3236. #define PRT_RESOURCE_ENCODING        "VIM-Encoding-EBCDIC 1.0 0"
  3237. #define PRT_RESOURCE_ENCODING_FILE    "evebcdic.ps"
  3238. #else /* !EBCDIC */
  3239. #define PRT_RESOURCE_ENCODING        "VIM-Encoding-ISOLatin1 1.0 0"
  3240. #define PRT_RESOURCE_ENCODING_FILE    "eviso.ps"
  3241. #endif /* !EBCDIC */
  3242. #endif /* !VMS */
  3243. #endif /* !MACOS */
  3244. #endif /* !WIN32 */
  3245.  
  3246. static void prt_write_file_raw_len __ARGS((char_u *buffer, int bytes));
  3247. static void prt_write_file __ARGS((char_u *buffer));
  3248. static void prt_write_file_len __ARGS((char_u *buffer, int bytes));
  3249. static void prt_write_string __ARGS((char *s));
  3250. static void prt_write_int __ARGS((int i));
  3251. static void prt_write_boolean __ARGS((int b));
  3252. static void prt_def_font __ARGS((char *new_name, int height, char *font));
  3253. static void prt_real_bits __ARGS((double real, int precision, int *pinteger, int *pfraction));
  3254. static void prt_write_real __ARGS((double val, int prec));
  3255. static void prt_def_var __ARGS((char *name, double value, int prec));
  3256. static void prt_flush_buffer __ARGS((void));
  3257. static void prt_dsc_start __ARGS((void));
  3258. static void prt_dsc_noarg __ARGS((char *comment));
  3259. static void prt_dsc_textline __ARGS((char *comment, char *text));
  3260. static void prt_dsc_text __ARGS((char *comment, char *text));
  3261. static void prt_dsc_ints __ARGS((char *comment, int count, int *ints));
  3262. static void prt_dsc_requirements __ARGS((int duplex, int tumble, int collate, int color, int num_copies));
  3263. static void prt_dsc_docmedia __ARGS((char *paper_name, double width, double height, double weight, char *colour, char *type));
  3264. static void prt_dsc_resources __ARGS((char *comment, char *type, int count, char **strings));
  3265. static float to_device_units __ARGS((int idx, double physsize, int def_number));
  3266. static void prt_page_margins __ARGS((double width, double height, double *left, double *right, double *top, double *bottom));
  3267. static void prt_font_metrics __ARGS((int font_scale));
  3268. static int prt_get_cpl __ARGS((void));
  3269. static int prt_get_lpp __ARGS((void));
  3270. static int prt_add_resource __ARGS((char *type, char *name, char *file));
  3271.  
  3272. /*
  3273.  * Variables for the output PostScript file.
  3274.  */
  3275. static FILE *prt_ps_fd;
  3276. static int prt_file_error;
  3277. static char_u *prt_ps_file_name = NULL;
  3278.  
  3279. /*
  3280.  * Various offsets and dimensions in default PostScript user space (points).
  3281.  * Used for text positioning calculations
  3282.  */
  3283. static float prt_page_width;
  3284. static float prt_page_height;
  3285. static float prt_left_margin;
  3286. static float prt_right_margin;
  3287. static float prt_top_margin;
  3288. static float prt_bottom_margin;
  3289. static float prt_line_height;
  3290. static float prt_first_line_height;
  3291. static float prt_char_width;
  3292. static float prt_number_width;
  3293. static float prt_bgcol_offset;
  3294. static float prt_pos_x_moveto = 0.0;
  3295. static float prt_pos_y_moveto = 0.0;
  3296.  
  3297. /*
  3298.  * Various control variables used to decide when and how to change the
  3299.  * PostScript graphics state.
  3300.  */
  3301. static int prt_need_moveto;
  3302. static int prt_do_moveto;
  3303. static int prt_need_font;
  3304. static int prt_font;
  3305. static int prt_need_underline;
  3306. static int prt_underline;
  3307. static int prt_do_underline;
  3308. static int prt_need_fgcol;
  3309. static int prt_fgcol;
  3310. static int prt_need_bgcol;
  3311. static int prt_do_bgcol;
  3312. static int prt_bgcol;
  3313. static int prt_new_bgcol;
  3314. static int prt_attribute_change;
  3315. static int prt_text_count;
  3316. static int prt_page_num;
  3317.  
  3318. /*
  3319.  * Variables controlling physical printing.
  3320.  */
  3321. static int prt_media;
  3322. static int prt_portrait;
  3323. static int prt_num_copies;
  3324. static int prt_duplex;
  3325. static int prt_tumble;
  3326. static int prt_collate;
  3327.  
  3328. /*
  3329.  * Buffers used when generating PostScript output
  3330.  */
  3331. static char_u prt_line_buffer[257];
  3332. static garray_T prt_ps_buffer;
  3333.  
  3334.  
  3335.     static void
  3336. prt_write_file_raw_len(buffer, bytes)
  3337.     char_u    *buffer;
  3338.     int        bytes;
  3339. {
  3340.     if (!prt_file_error
  3341.         && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd)
  3342.                                  != (size_t)bytes)
  3343.     {
  3344.     EMSG(_("E455: Error writing to PostScript output file"));
  3345.     prt_file_error = TRUE;
  3346.     }
  3347. }
  3348.  
  3349.     static void
  3350. prt_write_file(buffer)
  3351.     char_u    *buffer;
  3352. {
  3353.     prt_write_file_len(buffer, STRLEN(buffer));
  3354. }
  3355.  
  3356.     static void
  3357. prt_write_file_len(buffer, bytes)
  3358.     char_u    *buffer;
  3359.     int        bytes;
  3360. {
  3361. #ifdef EBCDIC
  3362.     ebcdic2ascii(buffer, bytes);
  3363. #endif
  3364.     prt_write_file_raw_len(buffer, bytes);
  3365. }
  3366.  
  3367. /*
  3368.  * Write a string.
  3369.  */
  3370.     static void
  3371. prt_write_string(s)
  3372.     char    *s;
  3373. {
  3374.     sprintf((char *)prt_line_buffer, "%s", s);
  3375.     prt_write_file(prt_line_buffer);
  3376. }
  3377.  
  3378. /*
  3379.  * Write an int and a space.
  3380.  */
  3381.     static void
  3382. prt_write_int(i)
  3383.     int        i;
  3384. {
  3385.     sprintf((char *)prt_line_buffer, "%d ", i);
  3386.     prt_write_file(prt_line_buffer);
  3387. }
  3388.  
  3389. /*
  3390.  * Write a boolean and a space.
  3391.  */
  3392.     static void
  3393. prt_write_boolean(b)
  3394.     int        b;
  3395. {
  3396.     sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
  3397.     prt_write_file(prt_line_buffer);
  3398. }
  3399.  
  3400. /*
  3401.  * Write a line to define the font.
  3402.  */
  3403.     static void
  3404. prt_def_font(new_name, height, font)
  3405.     char    *new_name;
  3406.     int        height;
  3407.     char    *font;
  3408. {
  3409.     sprintf((char *)prt_line_buffer, "/_%s EV /%s ref\n", new_name, font);
  3410.     prt_write_file(prt_line_buffer);
  3411.     sprintf((char *)prt_line_buffer, "/%s %d /_%s ffs\n",
  3412.                             new_name, height, new_name);
  3413.     prt_write_file(prt_line_buffer);
  3414. }
  3415.  
  3416. /*
  3417.  * Convert a real value into an integer and fractional part as integers, with
  3418.  * the fractional part being in the range [0,10^precision).  The fractional part
  3419.  * is also rounded based on the precision + 1'th fractional digit.
  3420.  */
  3421.     static void
  3422. prt_real_bits(real, precision, pinteger, pfraction)
  3423.     double      real;
  3424.     int         precision;
  3425.     int         *pinteger;
  3426.     int         *pfraction;
  3427. {
  3428.     int     i;
  3429.     int     integer;
  3430.     float   fraction;
  3431.  
  3432.     integer = (int)real;
  3433.     fraction = (float)(real - integer);
  3434.     if (real < (double)integer)
  3435.         fraction = -fraction;
  3436.     for (i = 0; i < precision; i++)
  3437.         fraction *= 10.0;
  3438.  
  3439.     *pinteger = integer;
  3440.     *pfraction = (int)(fraction + 0.5);
  3441. }
  3442.  
  3443. /*
  3444.  * Write a real and a space.  Save bytes if real value has no fractional part!
  3445.  * We use prt_real_bits() as %f in sprintf uses the locale setting to decide
  3446.  * what decimal point character to use, but PS always requires a '.'.
  3447.  */
  3448.     static void
  3449. prt_write_real(val, prec)
  3450.     double    val;
  3451.     int        prec;
  3452. {
  3453.     int     integer;
  3454.     int     fraction;
  3455.  
  3456.     prt_real_bits(val, prec, &integer, &fraction);
  3457.     /* Emit integer part */
  3458.     sprintf((char *)prt_line_buffer, "%d", integer);
  3459.     prt_write_file(prt_line_buffer);
  3460.     /* Only emit fraction if necessary */
  3461.     if (fraction != 0)
  3462.     {
  3463.         /* Remove any trailing zeros */
  3464.         while ((fraction % 10) == 0)
  3465.         {
  3466.             prec--;
  3467.             fraction /= 10;
  3468.         }
  3469.         /* Emit fraction left padded with zeros */
  3470.         sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction);
  3471.         prt_write_file(prt_line_buffer);
  3472.     }
  3473.     sprintf((char *)prt_line_buffer, " ");
  3474.     prt_write_file(prt_line_buffer);
  3475. }
  3476.  
  3477. /*
  3478.  * Write a line to define a numeric variable.
  3479.  */
  3480.     static void
  3481. prt_def_var(name, value, prec)
  3482.     char    *name;
  3483.     double    value;
  3484.     int        prec;
  3485. {
  3486.     sprintf((char *)prt_line_buffer, "/%s ", name);
  3487.     prt_write_file(prt_line_buffer);
  3488.     prt_write_real(value, prec);
  3489.     sprintf((char *)prt_line_buffer, "d\n");
  3490.     prt_write_file(prt_line_buffer);
  3491. }
  3492.  
  3493. /* Convert size from font space to user space at current font scale */
  3494. #define PRT_PS_FONT_TO_USER(scale, size)    ((size) * ((scale)/1000.0))
  3495.  
  3496.     static void
  3497. prt_flush_buffer()
  3498. {
  3499.     if (prt_ps_buffer.ga_len > 0)
  3500.     {
  3501.     /* Any background color must be drawn first */
  3502.     if (prt_do_bgcol && (prt_new_bgcol != COLOR_WHITE))
  3503.     {
  3504.         int     r, g, b;
  3505.  
  3506.         if (prt_do_moveto)
  3507.         {
  3508.         prt_write_real(prt_pos_x_moveto, 2);
  3509.         prt_write_real(prt_pos_y_moveto, 2);
  3510.         prt_write_string("m\n");
  3511.         prt_do_moveto = FALSE;
  3512.         }
  3513.  
  3514.         /* Size of rect of background color on which text is printed */
  3515.         prt_write_real(prt_text_count * prt_char_width, 2);
  3516.         prt_write_real(prt_line_height, 2);
  3517.  
  3518.         /* Lastly add the color of the background */
  3519.         r = ((unsigned)prt_new_bgcol & 0xff0000) >> 16;
  3520.         g = ((unsigned)prt_new_bgcol & 0xff00) >> 8;
  3521.         b = prt_new_bgcol & 0xff;
  3522.         prt_write_real(r / 255.0, 3);
  3523.         prt_write_real(g / 255.0, 3);
  3524.         prt_write_real(b / 255.0, 3);
  3525.         prt_write_string("bg\n");
  3526.     }
  3527.     /* Draw underlines before the text as it makes it slightly easier to
  3528.      * find the starting point.
  3529.      */
  3530.     if (prt_do_underline)
  3531.     {
  3532.         if (prt_do_moveto)
  3533.         {
  3534.         prt_write_real(prt_pos_x_moveto, 2);
  3535.         prt_write_real(prt_pos_y_moveto, 2);
  3536.         prt_write_string("m\n");
  3537.         prt_do_moveto = FALSE;
  3538.         }
  3539.  
  3540.         /* Underlining is easy - just need the number of characters to
  3541.          * print. */
  3542.         prt_write_real(prt_text_count * prt_char_width, 2);
  3543.         prt_write_string("ul\n");
  3544.     }
  3545.     /* Draw the text
  3546.      * Note: we write text out raw - EBCDIC conversion is handled in the
  3547.      * PostScript world via the font encoding vector. */
  3548.     prt_write_string("(");
  3549.     prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len);
  3550.     prt_write_string(")");
  3551.     /* Add a moveto if need be and use the appropriate show procedure */
  3552.     if (prt_do_moveto)
  3553.     {
  3554.         prt_write_real(prt_pos_x_moveto, 2);
  3555.         prt_write_real(prt_pos_y_moveto, 2);
  3556.         /* moveto and a show */
  3557.         prt_write_string("ms\n");
  3558.         prt_do_moveto = FALSE;
  3559.     }
  3560.     else /* Simple show */
  3561.         prt_write_string("s\n");
  3562.  
  3563.     ga_clear(&prt_ps_buffer);
  3564.     ga_init2(&prt_ps_buffer, (int)sizeof(char), PRT_PS_DEFAULT_BUFFER_SIZE);
  3565.     }
  3566. }
  3567.  
  3568.     static void
  3569. prt_dsc_start()
  3570. {
  3571.     prt_write_string("%!PS-Adobe-3.0\n");
  3572. }
  3573.  
  3574.     static void
  3575. prt_dsc_noarg(comment)
  3576.     char    *comment;
  3577. {
  3578.     sprintf((char *)prt_line_buffer, "%%%%%s\n", comment);
  3579.     prt_write_file(prt_line_buffer);
  3580. }
  3581.  
  3582.     static void
  3583. prt_dsc_textline(comment, text)
  3584.     char    *comment;
  3585.     char    *text;
  3586. {
  3587.     sprintf((char *)prt_line_buffer, "%%%%%s: %s\n", comment, text);
  3588.     prt_write_file(prt_line_buffer);
  3589. }
  3590.  
  3591.     static void
  3592. prt_dsc_text(comment, text)
  3593.     char    *comment;
  3594.     char    *text;
  3595. {
  3596.     /* TODO - should scan 'text' for any chars needing escaping! */
  3597.     sprintf((char *)prt_line_buffer, "%%%%%s: (%s)\n", comment, text);
  3598.     prt_write_file(prt_line_buffer);
  3599. }
  3600.  
  3601. #define prt_dsc_atend(c)    prt_dsc_text((c), "atend")
  3602.  
  3603.     static void
  3604. prt_dsc_ints(comment, count, ints)
  3605.     char    *comment;
  3606.     int        count;
  3607.     int        *ints;
  3608. {
  3609.     int        i;
  3610.  
  3611.     sprintf((char *)prt_line_buffer, "%%%%%s:", comment);
  3612.     prt_write_file(prt_line_buffer);
  3613.  
  3614.     for (i = 0; i < count; i++)
  3615.     {
  3616.     sprintf((char *)prt_line_buffer, " %d", ints[i]);
  3617.     prt_write_file(prt_line_buffer);
  3618.     }
  3619.  
  3620.     prt_write_string("\n");
  3621. }
  3622.  
  3623.     static void
  3624. prt_dsc_resources(comment, type, count, strings)
  3625.     char    *comment;    /* if NULL add to previous */
  3626.     char    *type;
  3627.     int        count;
  3628.     char    **strings;
  3629. {
  3630.     int        i;
  3631.  
  3632.     if (comment != NULL)
  3633.     sprintf((char *)prt_line_buffer, "%%%%%s: %s", comment, type);
  3634.     else
  3635.     sprintf((char *)prt_line_buffer, "%%%%+ %s", type);
  3636.     prt_write_file(prt_line_buffer);
  3637.  
  3638.     for (i = 0; i < count; i++)
  3639.     {
  3640.     sprintf((char *)prt_line_buffer, " %s", strings[i]);
  3641.     prt_write_file(prt_line_buffer);
  3642.     }
  3643.  
  3644.     prt_write_string("\n");
  3645. }
  3646.  
  3647.     static void
  3648. prt_dsc_requirements(duplex, tumble, collate, color, num_copies)
  3649.     int        duplex;
  3650.     int        tumble;
  3651.     int        collate;
  3652.     int        color;
  3653.     int        num_copies;
  3654. {
  3655.     /* Only output the comment if we need to.
  3656.      * Note: tumble is ignored if we are not duplexing
  3657.      */
  3658.     if (!(duplex || collate || color || (num_copies > 1)))
  3659.     return;
  3660.  
  3661.     sprintf((char *)prt_line_buffer, "%%%%Requirements:");
  3662.     prt_write_file(prt_line_buffer);
  3663.  
  3664.     if (duplex)
  3665.     {
  3666.     prt_write_string(" duplex");
  3667.     if (tumble)
  3668.         prt_write_string("(tumble)");
  3669.     }
  3670.     if (collate)
  3671.     prt_write_string(" collate");
  3672.     if (color)
  3673.     prt_write_string(" color");
  3674.     if (num_copies > 1)
  3675.     {
  3676.     prt_write_string(" numcopies(");
  3677.     /* Note: no space wanted so dont use prt_write_int() */
  3678.     sprintf((char *)prt_line_buffer, "%d", num_copies);
  3679.     prt_write_file(prt_line_buffer);
  3680.     prt_write_string(")");
  3681.     }
  3682.     prt_write_string("\n");
  3683. }
  3684.  
  3685.     static void
  3686. prt_dsc_docmedia(paper_name, width, height, weight, colour, type)
  3687.     char    *paper_name;
  3688.     double    width;
  3689.     double    height;
  3690.     double    weight;
  3691.     char    *colour;
  3692.     char    *type;
  3693. {
  3694.     sprintf((char *)prt_line_buffer, "%%%%DocumentMedia: %s ", paper_name);
  3695.     prt_write_file(prt_line_buffer);
  3696.     prt_write_real(width, 2);
  3697.     prt_write_real(height, 2);
  3698.     prt_write_real(weight, 2);
  3699.     if (colour == NULL)
  3700.     prt_write_string("()");
  3701.     else
  3702.     prt_write_string(colour);
  3703.     prt_write_string(" ");
  3704.     if (type == NULL)
  3705.     prt_write_string("()");
  3706.     else
  3707.     prt_write_string(type);
  3708.     prt_write_string("\n");
  3709. }
  3710.  
  3711.     void
  3712. mch_print_cleanup()
  3713. {
  3714.     if (prt_ps_fd != NULL)
  3715.     {
  3716.     fclose(prt_ps_fd);
  3717.     prt_ps_fd = NULL;
  3718.     prt_file_error = FALSE;
  3719.     }
  3720.     if (prt_ps_file_name != NULL)
  3721.     {
  3722.     vim_free(prt_ps_file_name);
  3723.     prt_ps_file_name = NULL;
  3724.     }
  3725. }
  3726.  
  3727.     static float
  3728. to_device_units(idx, physsize, def_number)
  3729.     int        idx;
  3730.     double    physsize;
  3731.     int        def_number;
  3732. {
  3733.     float    ret;
  3734.     int        u;
  3735.     int        nr;
  3736.  
  3737.     u = prt_get_unit(idx);
  3738.     if (u == PRT_UNIT_NONE)
  3739.     {
  3740.     u = PRT_UNIT_PERC;
  3741.     nr = def_number;
  3742.     }
  3743.     else
  3744.     nr = printer_opts[idx].number;
  3745.  
  3746.     switch (u)
  3747.     {
  3748.     case PRT_UNIT_INCH:
  3749.         ret = (float)(nr * PRT_PS_DEFAULT_DPI);
  3750.         break;
  3751.     case PRT_UNIT_MM:
  3752.         ret = (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4;
  3753.         break;
  3754.     case PRT_UNIT_POINT:
  3755.         ret = (float)nr;
  3756.         break;
  3757.     case PRT_UNIT_PERC:
  3758.     default:
  3759.         ret = (float)(physsize * nr) / 100;
  3760.         break;
  3761.     }
  3762.  
  3763.     return ret;
  3764. }
  3765.  
  3766. /*
  3767.  * Calculate margins for given width and height from printoptions settings.
  3768.  */
  3769.     static void
  3770. prt_page_margins(width, height, left, right, top, bottom)
  3771.     double    width;
  3772.     double    height;
  3773.     double    *left;
  3774.     double    *right;
  3775.     double    *top;
  3776.     double    *bottom;
  3777. {
  3778.     *left   = to_device_units(OPT_PRINT_LEFT, width, 10);
  3779.     *right  = width - to_device_units(OPT_PRINT_RIGHT, width, 5);
  3780.     *top    = height - to_device_units(OPT_PRINT_TOP, height, 5);
  3781.     *bottom = to_device_units(OPT_PRINT_BOT, height, 5);
  3782. }
  3783.  
  3784.     static void
  3785. prt_font_metrics(font_scale)
  3786.     int        font_scale;
  3787. {
  3788.     prt_line_height = (float)font_scale;
  3789.     prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font.wx);
  3790. }
  3791.  
  3792.  
  3793.     static int
  3794. prt_get_cpl()
  3795. {
  3796.     if (prt_use_number())
  3797.     {
  3798.     prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width;
  3799.     prt_left_margin += prt_number_width;
  3800.     }
  3801.     else
  3802.     prt_number_width = 0.0;
  3803.  
  3804.     return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
  3805. }
  3806.  
  3807. /*
  3808.  * Get number of lines of text that fit on a page (excluding the header).
  3809.  */
  3810.     static int
  3811. prt_get_lpp()
  3812. {
  3813.     int lpp;
  3814.  
  3815.     /*
  3816.      * Calculate offset to lower left corner of background rect based on actual
  3817.      * font height (based on its bounding box) and the line height, handling the
  3818.      * case where the font height can exceed the line height.
  3819.      */
  3820.     prt_bgcol_offset = (float)PRT_PS_FONT_TO_USER(prt_line_height,
  3821.                        prt_ps_font.bbox_min_y);
  3822.     if ((prt_ps_font.bbox_max_y - prt_ps_font.bbox_min_y) < 1000.0)
  3823.     {
  3824.     prt_bgcol_offset -= (float)PRT_PS_FONT_TO_USER(prt_line_height,
  3825.                 (1000.0 - (prt_ps_font.bbox_max_y -
  3826.                         prt_ps_font.bbox_min_y)) / 2);
  3827.     }
  3828.  
  3829.     /* Get height for topmost line based on background rect offset. */
  3830.     prt_first_line_height = prt_line_height + prt_bgcol_offset;
  3831.  
  3832.     /* Calculate lpp */
  3833.     lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height);
  3834.  
  3835.     /* Adjust top margin if there is a header */
  3836.     prt_top_margin -= prt_line_height * prt_header_height();
  3837.  
  3838.     return lpp - prt_header_height();
  3839. }
  3840.  
  3841. /*ARGSUSED*/
  3842.     int
  3843. mch_print_init(psettings, jobname, forceit)
  3844.     prt_settings_T *psettings;
  3845.     char_u    *jobname;
  3846.     int        forceit;
  3847. {
  3848.     int        i;
  3849.     char    *paper_name;
  3850.     int        paper_strlen;
  3851.     int        fontsize;
  3852.     char_u    *p;
  3853.     double      left;
  3854.     double      right;
  3855.     double      top;
  3856.     double      bottom;
  3857.  
  3858. #if 0
  3859.     /*
  3860.      * TODO:
  3861.      * If "forceit" is false: pop up a dialog to select:
  3862.      *    - printer name
  3863.      *    - copies
  3864.      *    - collated/uncollated
  3865.      *    - duplex off/long side/short side
  3866.      *    - paper size
  3867.      *    - portrait/landscape
  3868.      *    - font size
  3869.      *
  3870.      * If "forceit" is true: use the default printer and settings
  3871.      */
  3872.     if (forceit)
  3873.     s_pd.Flags |= PD_RETURNDEFAULT;
  3874. #endif
  3875.  
  3876.     /*
  3877.      * Find the size of the paper and set the margins.
  3878.      */
  3879.     prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present
  3880.           || TO_LOWER(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y');
  3881.     if (printer_opts[OPT_PRINT_PAPER].present)
  3882.     {
  3883.     paper_name = (char *)printer_opts[OPT_PRINT_PAPER].string;
  3884.     paper_strlen = printer_opts[OPT_PRINT_PAPER].strlen;
  3885.     }
  3886.     else
  3887.     {
  3888.     paper_name = "A4";
  3889.     paper_strlen = 2;
  3890.     }
  3891.     for (i = 0; i < PRT_MEDIASIZE_LEN; ++i)
  3892.     if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen
  3893.         && STRNICMP(prt_mediasize[i].name, paper_name,
  3894.                                paper_strlen) == 0)
  3895.         break;
  3896.     if (i == PRT_MEDIASIZE_LEN)
  3897.     i = 0;
  3898.     prt_media = i;
  3899.  
  3900.     /*
  3901.      * Set PS pagesize based on media dimensions and print orientation.
  3902.      * Note: Media and page sizes have defined meanings in PostScript and should
  3903.      * be kept distinct.  Media is the paper (or transparency, or ...) that is
  3904.      * printed on, whereas the page size is the area that the PostScript
  3905.      * interpreter renders into.
  3906.      */
  3907.     if (prt_portrait)
  3908.     {
  3909.     prt_page_width = prt_mediasize[i].width;
  3910.     prt_page_height = prt_mediasize[i].height;
  3911.     }
  3912.     else
  3913.     {
  3914.     prt_page_width = prt_mediasize[i].height;
  3915.     prt_page_height = prt_mediasize[i].width;
  3916.     }
  3917.  
  3918.     /*
  3919.      * Set PS page margins based on the PS pagesize, not the mediasize - this
  3920.      * needs to be done before the cpl and lpp are calculated.
  3921.      */
  3922.     prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top,
  3923.                                     &bottom);
  3924.     prt_left_margin = (float)left;
  3925.     prt_right_margin = (float)right;
  3926.     prt_top_margin = (float)top;
  3927.     prt_bottom_margin = (float)bottom;
  3928.  
  3929.     /*
  3930.      * Set up the font size.
  3931.      */
  3932.     fontsize = PRT_PS_DEFAULT_FONTSIZE;
  3933.     for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p)
  3934.     if (p[1] == 'h' && isdigit(p[2]))
  3935.         fontsize = atoi((char *)p + 2);
  3936.     prt_font_metrics(fontsize);
  3937.  
  3938.     /*
  3939.      * Return the number of characters per line, and lines per page for the
  3940.      * generic print code.
  3941.      */
  3942.     psettings->chars_per_line = prt_get_cpl();
  3943.     psettings->lines_per_page = prt_get_lpp();
  3944.  
  3945.     /* Catch margin settings that leave no space for output! */
  3946.     if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0)
  3947.     return FAIL;
  3948.  
  3949.     /*
  3950.      * Sort out the number of copies to be printed.  PS by default will do
  3951.      * uncollated copies for you, so once we know how many uncollated copies are
  3952.      * wanted cache it away and lie to the generic code that we only want one
  3953.      * uncollated copy.
  3954.      */
  3955.     psettings->n_collated_copies = 1;
  3956.     psettings->n_uncollated_copies = 1;
  3957.     prt_num_copies = 1;
  3958.     prt_collate = (!printer_opts[OPT_PRINT_COLLATE].present
  3959.         || TO_LOWER(printer_opts[OPT_PRINT_COLLATE].string[0]) == 'y');
  3960.     if (prt_collate)
  3961.     {
  3962.     /* TODO: Get number of collated copies wanted. */
  3963.     psettings->n_collated_copies = 1;
  3964.     }
  3965.     else
  3966.     {
  3967.     /* TODO: Get number of uncollated copies wanted and update the cached
  3968.      * count.
  3969.      */
  3970.     prt_num_copies = 1;
  3971.     }
  3972.  
  3973.     psettings->jobname = jobname;
  3974.  
  3975.     /*
  3976.      * Set up printer duplex and tumble based on Duplex option setting - default
  3977.      * is long sided duplex printing (i.e. no tumble).
  3978.      */
  3979.     prt_duplex = TRUE;
  3980.     prt_tumble = FALSE;
  3981.     psettings->duplex = 1;
  3982.     if (printer_opts[OPT_PRINT_DUPLEX].present)
  3983.     {
  3984.     if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0)
  3985.     {
  3986.         prt_duplex = FALSE;
  3987.         psettings->duplex = 0;
  3988.     }
  3989.     else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
  3990.                                      == 0)
  3991.         prt_tumble = TRUE;
  3992.     }
  3993.  
  3994.     /* For now user abort not supported */
  3995.     psettings->user_abort = 0;
  3996.  
  3997.     /* If the user didn't specify a file name, use a temp file. */
  3998.     if (psettings->outfile == NULL)
  3999.     {
  4000.     prt_ps_file_name = vim_tempname('p');
  4001.     if (prt_ps_file_name == NULL)
  4002.     {
  4003.         EMSG(_(e_notmp));
  4004.         return FAIL;
  4005.     }
  4006.     prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN);
  4007.     }
  4008.     else
  4009.     {
  4010.     p = expand_env_save(psettings->outfile);
  4011.     if (p != NULL)
  4012.     {
  4013.         prt_ps_fd = mch_fopen((char *)p, WRITEBIN);
  4014.         vim_free(p);
  4015.     }
  4016.     }
  4017.     if (prt_ps_fd == NULL)
  4018.     {
  4019.     EMSG(_("E324: Can't open PostScript output file"));
  4020.     mch_print_cleanup();
  4021.     return FAIL;
  4022.     }
  4023.  
  4024.     ga_init2(&prt_ps_buffer, (int)sizeof(char), PRT_PS_DEFAULT_BUFFER_SIZE);
  4025.  
  4026.     prt_page_num = 0;
  4027.  
  4028.     prt_attribute_change = FALSE;
  4029.     prt_need_moveto = FALSE;
  4030.     prt_need_font = FALSE;
  4031.     prt_need_fgcol = FALSE;
  4032.     prt_need_bgcol = FALSE;
  4033.     prt_need_underline = FALSE;
  4034.  
  4035.     prt_file_error = FALSE;
  4036.  
  4037.     return OK;
  4038. }
  4039.  
  4040.     static int
  4041. prt_add_resource(type, name, file)
  4042.     char    *type;
  4043.     char    *name;
  4044.     char    *file;
  4045. {
  4046.     FILE*    fd_resource;
  4047.     char_u    resource_buffer[128];
  4048.     char_u    resource_filename[MAXPATHL + 1];
  4049.     char    *resource_name[1];
  4050.     size_t    bytes_read;
  4051.  
  4052.     sprintf((char *)resource_buffer, "$VIMRUNTIME/%s", file);
  4053.     expand_env(resource_buffer, resource_filename, MAXPATHL);
  4054.     fd_resource = mch_fopen((char *)resource_filename, READBIN);
  4055.     if (fd_resource == NULL)
  4056.     {
  4057.     EMSG2(_("E456: Can't open file \"%s\""), resource_filename);
  4058.     return FALSE;
  4059.     }
  4060.     resource_name[0] = name;
  4061.     prt_dsc_resources("BeginResource", type, 1, resource_name);
  4062.     for (;;)
  4063.     {
  4064.     bytes_read = fread((char *)resource_buffer, sizeof(char_u),
  4065.                sizeof(resource_buffer), fd_resource);
  4066.     if (ferror(fd_resource))
  4067.     {
  4068.         EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
  4069.                                 resource_filename);
  4070.         fclose(fd_resource);
  4071.         return FALSE;
  4072.     }
  4073.     if (bytes_read == 0)
  4074.         break;
  4075.     prt_write_file_raw_len(resource_buffer, bytes_read);
  4076.     if (prt_file_error)
  4077.     {
  4078.         fclose(fd_resource);
  4079.         return FALSE;
  4080.     }
  4081.     }
  4082.     fclose(fd_resource);
  4083.  
  4084.     prt_dsc_noarg("EndResource");
  4085.  
  4086.     return TRUE;
  4087. }
  4088.  
  4089.     int
  4090. mch_print_begin(psettings)
  4091.     prt_settings_T *psettings;
  4092. {
  4093.     time_t    now;
  4094.     int        bbox[4];
  4095.     char    *p_time;
  4096.     char    *resource[1];
  4097.     double      left;
  4098.     double      right;
  4099.     double      top;
  4100.     double      bottom;
  4101.  
  4102.     /*
  4103.      * PS DSC Header comments - no PS code!
  4104.      */
  4105.     prt_dsc_start();
  4106.     prt_dsc_textline("Title", (char *)psettings->jobname);
  4107.     /* TODO - platform dependent user name retrieval */
  4108.     prt_dsc_textline("For", "Unknown");
  4109.     prt_dsc_textline("Creator", VIM_VERSION_LONG);
  4110.     /* Note: to ensure Clean8bit I don't think we can use LC_TIME */
  4111.     now = time(NULL);
  4112.     p_time = ctime(&now);
  4113.     /* Note: ctime() adds a \n so we have to remove it :-( */
  4114.     *(vim_strchr((char_u *)p_time, '\n')) = '\0';
  4115.     prt_dsc_textline("CreationDate", p_time);
  4116.     prt_dsc_textline("DocumentData", "Clean8Bit");
  4117.     prt_dsc_textline("Orientation", "Portrait");
  4118.     prt_dsc_atend("Pages");
  4119.     prt_dsc_textline("PageOrder", "Ascend");
  4120.     /* The bbox does not change with orientation - it is always in the default
  4121.      * user coordinate system!  We have to recalculate right and bottom
  4122.      * coordinates based on the font metrics for the bbox to be accurate. */
  4123.     prt_page_margins(prt_mediasize[prt_media].width,
  4124.                         prt_mediasize[prt_media].height,
  4125.                         &left, &right, &top, &bottom);
  4126.     bbox[0] = (int)left;
  4127.     if (prt_portrait)
  4128.     {
  4129.     /* In portrait printing the fixed point is the top left corner so we
  4130.      * derive the bbox from that point.  We have the expected cpl chars
  4131.      * across the media and lpp lines down the media.
  4132.      */
  4133.     bbox[1] = (int)(top - (psettings->lines_per_page + prt_header_height())
  4134.                                 * prt_line_height);
  4135.     bbox[2] = (int)(left + psettings->chars_per_line * prt_char_width
  4136.                                     + 0.5);
  4137.     bbox[3] = (int)(top + 0.5);
  4138.     }
  4139.     else
  4140.     {
  4141.     /* In landscape printing the fixed point is the bottom left corner so we
  4142.      * derive the bbox from that point.  We have lpp chars across the media
  4143.      * and cpl lines up the media.
  4144.      */
  4145.     bbox[1] = (int)bottom;
  4146.     bbox[2] = (int)(left + ((psettings->lines_per_page
  4147.                   + prt_header_height()) * prt_line_height) + 0.5);
  4148.     bbox[3] = (int)(bottom + psettings->chars_per_line * prt_char_width
  4149.                                     + 0.5);
  4150.     }
  4151.     prt_dsc_ints("BoundingBox", 4, bbox);
  4152.     /* The media width and height does not change with landscape printing! */
  4153.     prt_dsc_docmedia(prt_mediasize[prt_media].name,
  4154.                 prt_mediasize[prt_media].width,
  4155.                 prt_mediasize[prt_media].height,
  4156.                 (double)0, NULL, NULL);
  4157.     prt_dsc_resources("DocumentNeededResources", "font", 4,
  4158.                              prt_ps_font.ps_fontname);
  4159.     resource[0] = PRT_RESOURCE_PROLOG;
  4160.     prt_dsc_resources("DocumentSuppliedResources", "procset", 1, resource);
  4161.     resource[0] = PRT_RESOURCE_ENCODING;
  4162.     prt_dsc_resources(NULL, "encoding", 1, resource);
  4163.     prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
  4164.                     psettings->do_syntax, prt_num_copies);
  4165.     prt_dsc_noarg("EndComments");
  4166.  
  4167.     /*
  4168.      * PS Document page defaults
  4169.      */
  4170.     prt_dsc_noarg("BeginDefaults");
  4171.  
  4172.     /* List font resources most likely common to all pages */
  4173.     prt_dsc_resources("PageResources", "font", 4, prt_ps_font.ps_fontname);
  4174.     /* Paper will be used for all pages */
  4175.     prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name);
  4176.  
  4177.     prt_dsc_noarg("EndDefaults");
  4178.  
  4179.     /*
  4180.      * PS Document prolog inclusion - all required procsets.
  4181.      */
  4182.     prt_dsc_noarg("BeginProlog");
  4183.  
  4184.     /* For now there is just the one procset to be included in the PS file. */
  4185.     if (!prt_add_resource("procset", PRT_RESOURCE_PROLOG, "procset.ps"))
  4186.     return FALSE;
  4187.  
  4188.     /* There will be only one font encoding to be included in the PS file. */
  4189.     if (!prt_add_resource("encoding", PRT_RESOURCE_ENCODING,
  4190.                             PRT_RESOURCE_ENCODING_FILE))
  4191.     return FALSE;
  4192.  
  4193.     prt_dsc_noarg("EndProlog");
  4194.  
  4195.     /*
  4196.      * PS Document setup - must appear after the prolog
  4197.      */
  4198.     prt_dsc_noarg("BeginSetup");
  4199.  
  4200.     /* Device setup - page size and number of uncollated copies */
  4201.     prt_write_int((int)prt_mediasize[prt_media].width);
  4202.     prt_write_int((int)prt_mediasize[prt_media].height);
  4203.     prt_write_int(0);
  4204.     prt_write_string("sps\n");
  4205.     prt_write_int(prt_num_copies);
  4206.     prt_write_string("nc\n");
  4207.     prt_write_boolean(prt_duplex);
  4208.     prt_write_boolean(prt_tumble);
  4209.     prt_write_string("dt\n");
  4210.     prt_write_boolean(prt_collate);
  4211.     prt_write_string("c\n");
  4212.  
  4213.     /* Font resource inclusion and definition */
  4214.     prt_dsc_resources("IncludeResource", "font", 1,
  4215.                  &prt_ps_font.ps_fontname[PRT_PS_FONT_ROMAN]);
  4216.     prt_def_font("F0", (int)prt_line_height,
  4217.                   prt_ps_font.ps_fontname[PRT_PS_FONT_ROMAN]);
  4218.     prt_dsc_resources("IncludeResource", "font", 1,
  4219.                   &prt_ps_font.ps_fontname[PRT_PS_FONT_BOLD]);
  4220.     prt_def_font("F1", (int)prt_line_height,
  4221.                    prt_ps_font.ps_fontname[PRT_PS_FONT_BOLD]);
  4222.     prt_dsc_resources("IncludeResource", "font", 1,
  4223.                    &prt_ps_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
  4224.     prt_def_font("F2", (int)prt_line_height,
  4225.                 prt_ps_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
  4226.     prt_dsc_resources("IncludeResource", "font", 1,
  4227.                &prt_ps_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
  4228.     prt_def_font("F3", (int)prt_line_height,
  4229.                 prt_ps_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
  4230.  
  4231.     /* Misc constant vars used for underlining and background rects */
  4232.     prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
  4233.                         prt_ps_font.uline_offset), 2);
  4234.     prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
  4235.                          prt_ps_font.uline_width), 2);
  4236.     prt_def_var("BO", prt_bgcol_offset, 2);
  4237.  
  4238.     prt_dsc_noarg("EndSetup");
  4239.  
  4240.     /* Fail if any problems writing out to the PS file */
  4241.     return !prt_file_error;
  4242. }
  4243.  
  4244.     void
  4245. mch_print_end(psettings)
  4246.     prt_settings_T *psettings;
  4247. {
  4248.     prt_dsc_noarg("Trailer");
  4249.  
  4250.     /*
  4251.      * Output any info we don't know in toto until we finish
  4252.      */
  4253.     prt_dsc_ints("Pages", 1, &prt_page_num);
  4254.  
  4255.     prt_dsc_noarg("EOF");
  4256.  
  4257.     if (!prt_file_error && psettings->outfile == NULL
  4258.                     && !got_int && !psettings->user_abort)
  4259.     {
  4260.     /* Close the file first. */
  4261.     if (prt_ps_fd != NULL)
  4262.     {
  4263.         fclose(prt_ps_fd);
  4264.         prt_ps_fd = NULL;
  4265.     }
  4266.     prt_message((char_u *)_("Sending to printer..."));
  4267.  
  4268.     /* Not printing to a file: use 'printexpr' to print the file. */
  4269.     if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL)
  4270.         EMSG(_("E365: Failed to print PostScript file"));
  4271.     else
  4272.         prt_message((char_u *)_("Print job sent."));
  4273.     }
  4274.  
  4275.     mch_print_cleanup();
  4276. }
  4277.  
  4278.     int
  4279. mch_print_end_page()
  4280. {
  4281.     prt_flush_buffer();
  4282.  
  4283.     prt_write_string("re sp\n");
  4284.  
  4285.     prt_dsc_noarg("PageTrailer");
  4286.  
  4287.     return !prt_file_error;
  4288. }
  4289.  
  4290. /*ARGSUSED*/
  4291.     int
  4292. mch_print_begin_page(msg)
  4293.     char_u    *msg;
  4294. {
  4295.     int        page_num[2];
  4296.  
  4297.     prt_page_num++;
  4298.  
  4299.     page_num[0] = page_num[1] = prt_page_num;
  4300.     prt_dsc_ints("Page", 2, page_num);
  4301.  
  4302.     prt_dsc_noarg("BeginPageSetup");
  4303.  
  4304.     prt_write_string("sv\n0 g\nF0 sf\n");
  4305.     prt_fgcol = COLOR_BLACK;
  4306.     prt_bgcol = COLOR_WHITE;
  4307.     prt_font = PRT_PS_FONT_ROMAN;
  4308.  
  4309.     /* Set up page transformation for landscape printing. */
  4310.     if (!prt_portrait)
  4311.     {
  4312.     prt_write_int(-((int)prt_mediasize[prt_media].width));
  4313.     prt_write_string("sl\n");
  4314.     }
  4315.  
  4316.     prt_dsc_noarg("EndPageSetup");
  4317.  
  4318.     /* We have reset the font attributes, force setting them again. */
  4319.     curr_bg = (long_u)0xffffffff;
  4320.     curr_fg = (long_u)0xffffffff;
  4321.     curr_bold = MAYBE;
  4322.  
  4323.     return !prt_file_error;
  4324. }
  4325.  
  4326.     int
  4327. mch_print_blank_page()
  4328. {
  4329.     return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE);
  4330. }
  4331.  
  4332. static float prt_pos_x = 0;
  4333. static float prt_pos_y = 0;
  4334.  
  4335.     void
  4336. mch_print_start_line(margin, page_line)
  4337.     int        margin;
  4338.     int        page_line;
  4339. {
  4340.     prt_pos_x = prt_left_margin;
  4341.     if (margin)
  4342.     prt_pos_x -= prt_number_width;
  4343.  
  4344.     prt_pos_y = prt_top_margin - prt_first_line_height -
  4345.                     page_line * prt_line_height;
  4346.  
  4347.     prt_attribute_change = TRUE;
  4348.     prt_need_moveto = TRUE;
  4349. }
  4350.  
  4351. /*ARGSUSED*/
  4352.     int
  4353. mch_print_text_out(p, len)
  4354.     char_u    *p;
  4355.     int        len;
  4356. {
  4357.     int        need_break;
  4358.     char_u    ch;
  4359.     char_u      ch_buff[8];
  4360.  
  4361.     /* Output any required changes to the graphics state, after flushing any
  4362.      * text buffered so far.
  4363.      */
  4364.     if (prt_attribute_change)
  4365.     {
  4366.     prt_flush_buffer();
  4367.     /* Reset count of number of chars that will be printed */
  4368.     prt_text_count = 0;
  4369.  
  4370.     if (prt_need_moveto)
  4371.     {
  4372.         prt_pos_x_moveto = prt_pos_x;
  4373.         prt_pos_y_moveto = prt_pos_y;
  4374.         prt_do_moveto = TRUE;
  4375.  
  4376.         prt_need_moveto = FALSE;
  4377.     }
  4378.     if (prt_need_font)
  4379.     {
  4380.         prt_write_string("F");
  4381.         prt_write_int(prt_font);
  4382.         prt_write_string("sf\n");
  4383.         prt_need_font = FALSE;
  4384.     }
  4385.     if (prt_need_fgcol)
  4386.     {
  4387.         int     r, g, b;
  4388.         r = ((unsigned)prt_fgcol & 0xff0000) >> 16;
  4389.         g = ((unsigned)prt_fgcol & 0xff00) >> 8;
  4390.         b = prt_fgcol & 0xff;
  4391.  
  4392.         prt_write_real(r / 255.0, 3);
  4393.         if (r == g && g == b)
  4394.         {
  4395.         prt_write_string("g\n");
  4396.         }
  4397.         else
  4398.         {
  4399.         prt_write_real(g / 255.0, 3);
  4400.         prt_write_real(b / 255.0, 3);
  4401.         prt_write_string("r\n");
  4402.         }
  4403.         prt_need_fgcol = FALSE;
  4404.     }
  4405.  
  4406.     if (prt_bgcol != COLOR_WHITE)
  4407.     {
  4408.         prt_new_bgcol = prt_bgcol;
  4409.         if (prt_need_bgcol)
  4410.         prt_do_bgcol = TRUE;
  4411.     }
  4412.     else
  4413.         prt_do_bgcol = FALSE;
  4414.     prt_need_bgcol = FALSE;
  4415.  
  4416.     if (prt_need_underline)
  4417.         prt_do_underline = prt_underline;
  4418.     prt_need_underline = FALSE;
  4419.  
  4420.     prt_attribute_change = FALSE;
  4421.     }
  4422.  
  4423.     /* Add next character to buffer of characters to output.
  4424.      * Note: One printed character may require several PS characters to
  4425.      * represent it, but we only count them as one printed character.
  4426.      */
  4427.     ch = *p;
  4428.     /* Not handing multi-byte just yet, convert char to a blank for now */
  4429.     if (len > 1)
  4430.     ch = ' ';
  4431.     if (ch < 32 || ch == '(' || ch == ')' || ch == '\\')
  4432.     {
  4433.     /* Convert non-printing characters to either their escape or octal
  4434.      * sequence, ensures PS sent over a serial line does not interfere with
  4435.      * the comms protocol.
  4436.      * Note: For EBCDIC we need to write out the escape sequences as ASCII
  4437.      * codes!
  4438.      * Note 2: Char codes < 32 are identical in EBCDIC and ASCII AFAIK!
  4439.      */
  4440.     ga_append(&prt_ps_buffer, IF_EB('\\', 0134));
  4441.     switch (ch)
  4442.     {
  4443.         case BS:   ga_append(&prt_ps_buffer, IF_EB('b', 0142)); break;
  4444.         case TAB:  ga_append(&prt_ps_buffer, IF_EB('t', 0164)); break;
  4445.         case NL:   ga_append(&prt_ps_buffer, IF_EB('n', 0156)); break;
  4446.         case FF:   ga_append(&prt_ps_buffer, IF_EB('f', 0146)); break;
  4447.         case CR:   ga_append(&prt_ps_buffer, IF_EB('r', 0162)); break;
  4448.         case '(':  ga_append(&prt_ps_buffer, IF_EB('(', 0050)); break;
  4449.         case ')':  ga_append(&prt_ps_buffer, IF_EB(')', 0051)); break;
  4450.         case '\\': ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); break;
  4451.  
  4452.         default:
  4453.                sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
  4454. #ifdef EBCDIC
  4455.                ebcdic2ascii(ch_buff, 3);
  4456. #endif
  4457.                ga_append(&prt_ps_buffer, ch_buff[0]);
  4458.                ga_append(&prt_ps_buffer, ch_buff[1]);
  4459.                ga_append(&prt_ps_buffer, ch_buff[2]);
  4460.                break;
  4461.     }
  4462.     }
  4463.     else
  4464.     ga_append(&prt_ps_buffer, ch);
  4465.     prt_text_count++;
  4466.     prt_pos_x += prt_char_width;
  4467.  
  4468.     /* The downside of fp - need a little tolerance in the right margin check */
  4469.     need_break = (prt_pos_x + prt_char_width > (prt_right_margin + 0.01));
  4470.  
  4471.     if (need_break)
  4472.     prt_flush_buffer();
  4473.  
  4474.     return need_break;
  4475. }
  4476.  
  4477.     void
  4478. mch_print_set_font(iBold, iItalic, iUnderline)
  4479.     int        iBold;
  4480.     int        iItalic;
  4481.     int        iUnderline;
  4482. {
  4483.     int        font = 0;
  4484.  
  4485.     if (iBold)
  4486.     font |= 0x01;
  4487.     if (iItalic)
  4488.     font |= 0x02;
  4489.  
  4490.     if (font != prt_font)
  4491.     {
  4492.     prt_font = font;
  4493.     prt_attribute_change = TRUE;
  4494.     prt_need_font = TRUE;
  4495.     }
  4496.     if (prt_underline != iUnderline)
  4497.     {
  4498.     prt_underline = iUnderline;
  4499.     prt_attribute_change = TRUE;
  4500.     prt_need_underline = TRUE;
  4501.     }
  4502. }
  4503.  
  4504.     void
  4505. mch_print_set_bg(bgcol)
  4506.     long_u    bgcol;
  4507. {
  4508.     prt_bgcol = bgcol;
  4509.     prt_attribute_change = TRUE;
  4510.     prt_need_bgcol = TRUE;
  4511. }
  4512.  
  4513.     void
  4514. mch_print_set_fg(fgcol)
  4515.     long_u    fgcol;
  4516. {
  4517.     if (fgcol != (long_u)prt_fgcol)
  4518.     {
  4519.     prt_fgcol = fgcol;
  4520.     prt_attribute_change = TRUE;
  4521.     prt_need_fgcol = TRUE;
  4522.     }
  4523. }
  4524.  
  4525. # endif /*FEAT_POSTSCRIPT*/
  4526. #endif /*FEAT_PRINTER*/
  4527.  
  4528.  
  4529. #ifdef FEAT_EVAL
  4530.  
  4531. # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
  4532. static char *get_locale_val __ARGS((int what));
  4533.  
  4534.     static char *
  4535. get_locale_val(what)
  4536.     int        what;
  4537. {
  4538.     char    *loc;
  4539.  
  4540.     /* Obtain the locale value from the libraries.  For DJGPP this is
  4541.      * redefined and it doesn't use the arguments. */
  4542.     loc = setlocale(what, NULL);
  4543.  
  4544. #  if defined(__BORLANDC__)
  4545.     if (loc != NULL)
  4546.     {
  4547.     char_u    *p;
  4548.  
  4549.     /* Borland returns something like "LC_CTYPE=<name>\n"
  4550.      * Let's try to fix that bug here... */
  4551.     p = vim_strchr(loc, '=');
  4552.     if (p != NULL)
  4553.     {
  4554.         loc = ++p;
  4555.         while (*p != NUL)    /* remove trailing newline */
  4556.         {
  4557.         if (*p < ' ')
  4558.         {
  4559.             *p = NUL;
  4560.             break;
  4561.         }
  4562.         ++p;
  4563.         }
  4564.     }
  4565.     }
  4566. #  endif
  4567.  
  4568.     return loc;
  4569. }
  4570. # endif
  4571.  
  4572. /*
  4573.  * Set the "v:lang" variable according to the current locale setting.
  4574.  * Also do "v:lc_time"and "v:ctype".
  4575.  */
  4576.     void
  4577. set_lang_var()
  4578. {
  4579.     char_u    *loc;
  4580.  
  4581. # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
  4582.     loc = (char_u *)get_locale_val(LC_CTYPE);
  4583. # else
  4584.     /* setlocale() not supported: use the default value */
  4585.     loc = (char_u *)"C";
  4586. # endif
  4587.     set_vim_var_string(VV_CTYPE, loc, -1);
  4588.  
  4589.     /* When LC_MESSAGES isn't defined use the value from LC_CTYPE. */
  4590. # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
  4591.     loc = (char_u *)get_locale_val(LC_MESSAGES);
  4592. # endif
  4593.     set_vim_var_string(VV_LANG, loc, -1);
  4594.  
  4595. # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
  4596.     loc = (char_u *)get_locale_val(LC_TIME);
  4597. # endif
  4598.     set_vim_var_string(VV_LC_TIME, loc, -1);
  4599. }
  4600. #endif
  4601.  
  4602. #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
  4603.     && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
  4604. /*
  4605.  * ":language":  Set the language (locale).
  4606.  */
  4607.     void
  4608. ex_language(eap)
  4609.     exarg_T    *eap;
  4610. {
  4611.     char    *loc;
  4612.     char_u    *p;
  4613.     char_u    *name;
  4614.     int        what = LC_ALL;
  4615.     char    *whatstr = "";
  4616.  
  4617.     name = eap->arg;
  4618.  
  4619.     /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
  4620.      * Allow abbreviation, but require at least 3 characters to avoid
  4621.      * confusion with a two letter language name "me" or "ct". */
  4622.     p = skiptowhite(eap->arg);
  4623.     if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
  4624.     {
  4625.     if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
  4626.     {
  4627. #ifdef LC_MESSAGES
  4628.         what = LC_MESSAGES;
  4629. #else
  4630.         what = LC_CTYPE;
  4631. #endif
  4632.         name = skipwhite(p);
  4633.         whatstr = "messages ";
  4634.     }
  4635.     else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
  4636.     {
  4637.         what = LC_CTYPE;
  4638.         name = skipwhite(p);
  4639.         whatstr = "ctype ";
  4640.     }
  4641.     else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
  4642.     {
  4643.         what = LC_TIME;
  4644.         name = skipwhite(p);
  4645.         whatstr = "time ";
  4646.     }
  4647.     }
  4648.  
  4649.     if (*name == NUL)
  4650.     {
  4651.     smsg((char_u *)_("Current %slanguage: \"%s\""),
  4652.         whatstr, setlocale(what, NULL));
  4653.     }
  4654.     else
  4655.     {
  4656.     loc = setlocale(what, (char *)name);
  4657.     if (loc == NULL)
  4658.         EMSG2(_("E197: Cannot set language to \"%s\""), name);
  4659.     else
  4660.     {
  4661. #ifdef HAVE_NL_MSG_CAT_CNTR
  4662.         /* Need to do this for GNU gettext, otherwise cached translations
  4663.          * will be used again. */
  4664.         extern int _nl_msg_cat_cntr;
  4665.  
  4666.         ++_nl_msg_cat_cntr;
  4667. #endif
  4668.         /* Reset $LC_ALL, otherwise it would overrule everyting. */
  4669.         vim_setenv((char_u *)"LC_ALL", (char_u *)"");
  4670.  
  4671.         if (what != LC_TIME)
  4672.         {
  4673.         /* Tell gettext() what to translate to.  It apparently doesn't
  4674.          * use the currently effective locale.  Also do this when
  4675.          * FEAT_GETTEXT isn't defined, so that shell commands use this
  4676.          * value. */
  4677.         if (what == LC_ALL)
  4678.             vim_setenv((char_u *)"LANG", name);
  4679.         if (what != LC_CTYPE)
  4680.             vim_setenv((char_u *)"LC_MESSAGES", name);
  4681.  
  4682.         /* Set $LC_CTYPE, because it overrules $LANG, and
  4683.          * gtk_set_locale() calls setlocale() again.  gnome_init()
  4684.          * sets $LC_CTYPE to "en_US" (that's a bug!). */
  4685. #ifdef LC_MESSAGES
  4686.         if (what != LC_MESSAGES)
  4687. #endif
  4688.             vim_setenv((char_u *)"LC_CTYPE", name);
  4689. # ifdef FEAT_GUI_GTK
  4690.         /* Let GTK know what locale we're using.  Not sure this is
  4691.          * really needed... */
  4692.         if (gui.in_use)
  4693.             (void)gtk_set_locale();
  4694. # endif
  4695.         }
  4696.  
  4697. # ifdef FEAT_EVAL
  4698.         /* Set v:lang, v:lc_time and v:ctype to the final result. */
  4699.         set_lang_var();
  4700. # endif
  4701.     }
  4702.     }
  4703. }
  4704.  
  4705. # if defined(FEAT_CMDL_COMPL) || defined(PROTO)
  4706. /*
  4707.  * Function given to ExpandGeneric() to obtain the possible arguments of the
  4708.  * ":language" command.
  4709.  */
  4710. /*ARGSUSED*/
  4711.     char_u *
  4712. get_lang_arg(xp, idx)
  4713.     expand_T    *xp;
  4714.     int        idx;
  4715. {
  4716.     if (idx == 0)
  4717.     return (char_u *)"messages";
  4718.     if (idx == 1)
  4719.     return (char_u *)"ctype";
  4720.     return NULL;
  4721. }
  4722. # endif
  4723.  
  4724. #endif
  4725.